Merge branch '0.8.x' into userdesign
Conflicts: actions/designsettings.php
This commit is contained in:
commit
4df1ea49ec
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
avatar/*
|
avatar/*
|
||||||
files/*
|
files/*
|
||||||
|
file/*
|
||||||
_darcs/*
|
_darcs/*
|
||||||
logs/*
|
logs/*
|
||||||
config.php
|
config.php
|
||||||
@ -16,3 +17,8 @@ dataobject.ini
|
|||||||
.buildpath
|
.buildpath
|
||||||
.project
|
.project
|
||||||
.settings
|
.settings
|
||||||
|
TODO.rym
|
||||||
|
config-*.php
|
||||||
|
good-config.php
|
||||||
|
lac08.log
|
||||||
|
php.log
|
||||||
|
125
README
125
README
@ -2,8 +2,8 @@
|
|||||||
README
|
README
|
||||||
------
|
------
|
||||||
|
|
||||||
Laconica 0.7.3 ("You Are The Everything")
|
Laconica 0.7.4 ("Can't Get There From Here")
|
||||||
7 April 2009
|
29 May 2009
|
||||||
|
|
||||||
This is the README file for Laconica, the Open Source microblogging
|
This is the README file for Laconica, the Open Source microblogging
|
||||||
platform. It includes installation instructions, descriptions of
|
platform. It includes installation instructions, descriptions of
|
||||||
@ -71,29 +71,29 @@ for additional terms.
|
|||||||
New this version
|
New this version
|
||||||
================
|
================
|
||||||
|
|
||||||
This is a minor bug-fix and feature release since version 0.7.2.1,
|
This is a minor bug-fix and feature release since version 0.7.3,
|
||||||
released Mar 11 2009. Notable changes this version:
|
released Apr 4 2009. Notable changes this version:
|
||||||
|
|
||||||
- A plugin to allow a templating language for customization
|
- Improved handling of UTF-8 characters. The new code is *not* backwards
|
||||||
- A plugin for Piwik Analytics engine
|
compatible by default; see "Upgrading" below for instructions on
|
||||||
- A bookmarklet for posting a notice about a Web page you're reading
|
converting existing databases to the correct character set.
|
||||||
- A welcome notice ('welcomebot') and default subscription for new users
|
- Unroll joins for large queries. This greatly enhanced database
|
||||||
- Support for SSL for some or all pages on the site
|
performance -- up to 50x for some queries -- at the expense of making
|
||||||
- Better handling of empty notice lists on many pages
|
an extra DB hit for some queries.
|
||||||
- Major improvements to the Twitter friend-sync offline processing
|
- Added an optional plugin to use WikiHashtags
|
||||||
- subscribers, subscriptions, groups are listed on the Personal page.
|
(http://hashtags.wikia.com/) for the sidebar on hashtag pages.
|
||||||
- "Invite" link restored to main menu
|
- Optimized Twitter friend synchronization.
|
||||||
- Better memory handling in FOAF output
|
- Better error handling for Ajax posting of notices, including
|
||||||
- Fix for SUP support (FriendFeed)
|
HTTP errors and timeouts.
|
||||||
- Correct and intelligent redirect HTTP status codes
|
- Experimental Comet plugin -- supports the cometd and the Bayeux
|
||||||
- Fix DB collations for search and sort
|
protocol. Using this plugin, you can show "real time" updates on the
|
||||||
- Better H1s and Titles using user full names
|
public and tag pages. However, server configuration is complex.
|
||||||
- Fixes to make the linkback plugin operational
|
- If queues are enabled, update inboxes and memcached off-line. Speeds
|
||||||
- Better indication that a notice is being published by Ajax (spinner)
|
up posting considerably.
|
||||||
- Better and unified Atom output
|
- Correctly shorten links posted through XMPP.
|
||||||
- Hiding "register" and "join now" messages when site is closed
|
- <link> elements for pagination, supported by some browsers like Opera.
|
||||||
- ping, twitter and facebook queuehandlers working better
|
- Corrected date format in search API.
|
||||||
- Updated RPM spec
|
- Made the public XRDS file work correctly.
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
=============
|
=============
|
||||||
@ -197,9 +197,9 @@ especially if you've previously installed PHP/MySQL packages.
|
|||||||
1. Unpack the tarball you downloaded on your Web server. Usually a
|
1. Unpack the tarball you downloaded on your Web server. Usually a
|
||||||
command like this will work:
|
command like this will work:
|
||||||
|
|
||||||
tar zxf laconica-0.7.3.tar.gz
|
tar zxf laconica-0.7.4.tar.gz
|
||||||
|
|
||||||
...which will make a laconica-0.7.3 subdirectory in your current
|
...which will make a laconica-0.7.4 subdirectory in your current
|
||||||
directory. (If you don't have shell access on your Web server, you
|
directory. (If you don't have shell access on your Web server, you
|
||||||
may have to unpack the tarball on your local computer and FTP the
|
may have to unpack the tarball on your local computer and FTP the
|
||||||
files to the server.)
|
files to the server.)
|
||||||
@ -207,7 +207,7 @@ especially if you've previously installed PHP/MySQL packages.
|
|||||||
2. Move the tarball to a directory of your choosing in your Web root
|
2. Move the tarball to a directory of your choosing in your Web root
|
||||||
directory. Usually something like this will work:
|
directory. Usually something like this will work:
|
||||||
|
|
||||||
mv laconica-0.7.3 /var/www/mublog
|
mv laconica-0.7.4 /var/www/mublog
|
||||||
|
|
||||||
This will make your Laconica instance available in the mublog path of
|
This will make your Laconica instance available in the mublog path of
|
||||||
your server, like "http://example.net/mublog". "microblog" or
|
your server, like "http://example.net/mublog". "microblog" or
|
||||||
@ -694,10 +694,17 @@ to users on a remote site. (Or not... it's not well tested.) The
|
|||||||
Upgrading
|
Upgrading
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
IMPORTANT NOTE: Laconica 0.7.4 introduced a fix for some
|
||||||
|
incorrectly-stored international characters ("UTF-8"). For new
|
||||||
|
installations, it will now store non-ASCII characters correctly.
|
||||||
|
However, older installations will have the incorrect storage, and will
|
||||||
|
consequently show up "wrong" in browsers. See below for how to deal
|
||||||
|
with this situation.
|
||||||
|
|
||||||
If you've been using Laconica 0.6, 0.5 or lower, or if you've been
|
If you've been using Laconica 0.6, 0.5 or lower, or if you've been
|
||||||
tracking the "git" version of the software, you will probably want
|
tracking the "git" version of the software, you will probably want
|
||||||
to upgrade and keep your existing data. There is no automated upgrade
|
to upgrade and keep your existing data. There is no automated upgrade
|
||||||
procedure in Laconica 0.7.3. Try these step-by-step instructions; read
|
procedure in Laconica 0.7.4. Try these step-by-step instructions; read
|
||||||
to the end first before trying them.
|
to the end first before trying them.
|
||||||
|
|
||||||
0. Download Laconica and set up all the prerequisites as if you were
|
0. Download Laconica and set up all the prerequisites as if you were
|
||||||
@ -783,6 +790,29 @@ problem.
|
|||||||
3. When fixup_inboxes is finished, you can set the enabled flag to
|
3. When fixup_inboxes is finished, you can set the enabled flag to
|
||||||
'true'.
|
'true'.
|
||||||
|
|
||||||
|
UTF-8 Database
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Laconica 0.7.4 introduced a fix for some incorrectly-stored
|
||||||
|
international characters ("UTF-8"). This fix is not
|
||||||
|
backwards-compatible; installations from before 0.7.4 will show
|
||||||
|
non-ASCII characters of old notices incorrectly. This section explains
|
||||||
|
what to do.
|
||||||
|
|
||||||
|
0. You can disable the new behaviour by setting the 'db''utf8' config
|
||||||
|
option to "false". You should only do this until you're ready to
|
||||||
|
convert your DB to the new format.
|
||||||
|
1. When you're ready to convert, you can run the fixup_utf8.php script
|
||||||
|
in the scripts/ subdirectory. If you've had the "new behaviour"
|
||||||
|
enabled (probably a good idea), you can give the ID of the first
|
||||||
|
"new" notice as a parameter, and only notices before that one will
|
||||||
|
be converted. Notices are converted in reverse chronological order,
|
||||||
|
so the most recent (and visible) ones will be converted first. The
|
||||||
|
script should work whether or not you have the 'db''utf8' config
|
||||||
|
option enabled.
|
||||||
|
2. When you're ready, set $config['db']['utf8'] to true, so that
|
||||||
|
new notices will be stored correctly.
|
||||||
|
|
||||||
Configuration options
|
Configuration options
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
@ -910,6 +940,10 @@ mirror: you can set this to an array of DSNs, like the above
|
|||||||
and adding the slaves to this array. Note that if you want some
|
and adding the slaves to this array. Note that if you want some
|
||||||
requests to go to the 'database' (master) server, you'll need
|
requests to go to the 'database' (master) server, you'll need
|
||||||
to include it in this array, too.
|
to include it in this array, too.
|
||||||
|
utf8: whether to talk to the database in UTF-8 mode. This is the default
|
||||||
|
with new installations, but older sites may want to turn it off
|
||||||
|
until they get their databases fixed up. See "UTF-8 database"
|
||||||
|
above for details.
|
||||||
|
|
||||||
syslog
|
syslog
|
||||||
------
|
------
|
||||||
@ -1162,6 +1196,37 @@ reporturl: URL to post statistics to. Defaults to Laconica developers'
|
|||||||
set 'run' to 'never' than to set this value to something
|
set 'run' to 'never' than to set this value to something
|
||||||
nonsensical.
|
nonsensical.
|
||||||
|
|
||||||
|
|
||||||
|
attachments
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The software lets users upload files with their notices. You can configure
|
||||||
|
the types of accepted files by mime types and a trio of quota options:
|
||||||
|
per file, per user (total), per user per month.
|
||||||
|
|
||||||
|
We suggest the use of the pecl file_info extension to handle mime type
|
||||||
|
detection.
|
||||||
|
|
||||||
|
supported: an array of mime types you accept to store and distribute,
|
||||||
|
like 'image/gif', 'video/mpeg', 'audio/mpeg', etc. Make sure you
|
||||||
|
setup your server to properly reckognize the types you want to
|
||||||
|
support.
|
||||||
|
|
||||||
|
For quotas, be sure you've set the upload_max_filesize and post_max_size
|
||||||
|
in php.ini to be large enough to handle your upload. In httpd.conf
|
||||||
|
(if you're using apache), check that the LimitRequestBody directive isn't
|
||||||
|
set too low (it's optional, so it may not be there at all).
|
||||||
|
|
||||||
|
file_quota: maximum size for a single file upload in bytes. A user can send
|
||||||
|
any amount of notices with attachments as long as each attachment
|
||||||
|
is smaller than file_quota.
|
||||||
|
user_quota: total size in bytes a user can store on this server. Each user
|
||||||
|
can store any number of files as long as their total size does
|
||||||
|
not exceed the user_quota.
|
||||||
|
monthly_quota: total size permitted in the current month. This is the total
|
||||||
|
size in bytes that a user can upload each month.
|
||||||
|
|
||||||
|
|
||||||
Troubleshooting
|
Troubleshooting
|
||||||
===============
|
===============
|
||||||
|
|
||||||
@ -1174,7 +1239,7 @@ repository (see below), and you get a compilation error ("unexpected
|
|||||||
T_STRING") in the browser, check to see that you don't have any
|
T_STRING") in the browser, check to see that you don't have any
|
||||||
conflicts in your code.
|
conflicts in your code.
|
||||||
|
|
||||||
If you upgraded to Laconica 0.7.3 without reading the "Notice inboxes"
|
If you upgraded to Laconica 0.7.4 without reading the "Notice inboxes"
|
||||||
section above, and all your users' 'Personal' tabs are empty, read the
|
section above, and all your users' 'Personal' tabs are empty, read the
|
||||||
"Notice inboxes" section above.
|
"Notice inboxes" section above.
|
||||||
|
|
||||||
@ -1265,6 +1330,8 @@ if anyone's been overlooked in error.
|
|||||||
* Ken Sedgwick
|
* Ken Sedgwick
|
||||||
* Brian Hendrickson
|
* Brian Hendrickson
|
||||||
* Tobias Diekershoff
|
* Tobias Diekershoff
|
||||||
|
* Dan Moore
|
||||||
|
* Fil
|
||||||
|
|
||||||
Thanks also to the developers of our upstream library code and to the
|
Thanks also to the developers of our upstream library code and to the
|
||||||
thousands of people who have tried out Identi.ca, installed Laconi.ca,
|
thousands of people who have tried out Identi.ca, installed Laconi.ca,
|
||||||
|
@ -67,6 +67,7 @@ class ApiAction extends Action
|
|||||||
$this->process_command();
|
$this->process_command();
|
||||||
} else {
|
} else {
|
||||||
# basic authentication failed
|
# basic authentication failed
|
||||||
|
common_log(LOG_WARNING, "Failed API auth attempt, nickname: $nickname.");
|
||||||
$this->show_basic_auth_error();
|
$this->show_basic_auth_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,8 +144,8 @@ class ApiAction extends Action
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (in_array($fullname, $bareauth)) {
|
if (in_array($fullname, $bareauth)) {
|
||||||
# bareauth: only needs auth if without an argument
|
# bareauth: only needs auth if without an argument or query param specifying user
|
||||||
if ($this->api_arg) {
|
if ($this->api_arg || $this->arg('id') || is_numeric($this->arg('user_id')) || $this->arg('screen_name')) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -179,14 +179,14 @@ class ConversationTree extends NoticeList
|
|||||||
|
|
||||||
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
||||||
$this->out->element('h2', null, _('Notices'));
|
$this->out->element('h2', null, _('Notices'));
|
||||||
$this->out->elementStart('ul', array('class' => 'notices'));
|
$this->out->elementStart('ol', array('class' => 'notices xoxo'));
|
||||||
|
|
||||||
if (array_key_exists('root', $this->tree)) {
|
if (array_key_exists('root', $this->tree)) {
|
||||||
$rootid = $this->tree['root'][0];
|
$rootid = $this->tree['root'][0];
|
||||||
$this->showNoticePlus($rootid);
|
$this->showNoticePlus($rootid);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ol');
|
||||||
$this->out->elementEnd('div');
|
$this->out->elementEnd('div');
|
||||||
|
|
||||||
return $cnt;
|
return $cnt;
|
||||||
@ -215,13 +215,13 @@ class ConversationTree extends NoticeList
|
|||||||
if (array_key_exists($id, $this->tree)) {
|
if (array_key_exists($id, $this->tree)) {
|
||||||
$children = $this->tree[$id];
|
$children = $this->tree[$id];
|
||||||
|
|
||||||
$this->out->elementStart('ul', array('class' => 'notices'));
|
$this->out->elementStart('ol', array('class' => 'notices'));
|
||||||
|
|
||||||
foreach ($children as $child) {
|
foreach ($children as $child) {
|
||||||
$this->showNoticePlus($child);
|
$this->showNoticePlus($child);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ol');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('li');
|
$this->out->elementEnd('li');
|
||||||
|
@ -68,7 +68,7 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
$this->elementStart('form', array('method' => 'POST',
|
$this->elementStart('form', array('method' => 'post',
|
||||||
'id' => 'form_settings_design',
|
'id' => 'form_settings_design',
|
||||||
'class' => 'form_settings',
|
'class' => 'form_settings',
|
||||||
'action' =>
|
'action' =>
|
||||||
@ -80,8 +80,8 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||||||
$this->element('legend', null, _('Change background image'));
|
$this->element('legend', null, _('Change background image'));
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->element('label', array('for' => 'design_ background-image_file'),
|
$this->element('label', array('for' => 'design_background-image_file'),
|
||||||
_('Upload file'));
|
_('Upload file'));
|
||||||
$this->element('input', array('name' => 'design_background-image_file',
|
$this->element('input', array('name' => 'design_background-image_file',
|
||||||
'type' => 'file',
|
'type' => 'file',
|
||||||
'id' => 'design_background-image_file'));
|
'id' => 'design_background-image_file'));
|
||||||
|
@ -115,7 +115,7 @@ class FacebookhomeAction extends FacebookAction
|
|||||||
$flink->foreign_id = $this->fbuid;
|
$flink->foreign_id = $this->fbuid;
|
||||||
$flink->service = FACEBOOK_SERVICE;
|
$flink->service = FACEBOOK_SERVICE;
|
||||||
$flink->created = common_sql_now();
|
$flink->created = common_sql_now();
|
||||||
$flink->set_flags(true, false, false);
|
$flink->set_flags(true, false, false, false);
|
||||||
|
|
||||||
$flink_id = $flink->insert();
|
$flink_id = $flink->insert();
|
||||||
|
|
||||||
@ -138,9 +138,6 @@ class FacebookhomeAction extends FacebookAction
|
|||||||
|
|
||||||
function setDefaults()
|
function setDefaults()
|
||||||
{
|
{
|
||||||
// A default prefix string for notices
|
|
||||||
$this->facebook->api_client->data_setUserPreference(
|
|
||||||
FACEBOOK_NOTICE_PREFIX, 'dented: ');
|
|
||||||
$this->facebook->api_client->data_setUserPreference(
|
$this->facebook->api_client->data_setUserPreference(
|
||||||
FACEBOOK_PROMPTED_UPDATE_PREF, 'false');
|
FACEBOOK_PROMPTED_UPDATE_PREF, 'false');
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('LACONICA')) { exit(1); }
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
require_once(INSTALLDIR.'/lib/facebookaction.php');
|
require_once(INSTALLDIR.'/lib/facebookaction.php');
|
||||||
|
|
||||||
@ -89,16 +91,6 @@ class FacebookinviteAction extends FacebookAction
|
|||||||
|
|
||||||
function showFormContent()
|
function showFormContent()
|
||||||
{
|
{
|
||||||
|
|
||||||
// Get a list of users who are already using the app for exclusion
|
|
||||||
$exclude_ids = $this->facebook->api_client->friends_getAppUsers();
|
|
||||||
$exclude_ids_csv = null;
|
|
||||||
|
|
||||||
// fbml needs these as a csv string, not an array
|
|
||||||
if ($exclude_ids) {
|
|
||||||
$exclude_ids_csv = implode(',', $exclude_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = sprintf(_('You have been invited to %s'), common_config('site', 'name')) .
|
$content = sprintf(_('You have been invited to %s'), common_config('site', 'name')) .
|
||||||
htmlentities('<fb:req-choice url="' . $this->app_uri . '" label="Add"/>');
|
htmlentities('<fb:req-choice url="' . $this->app_uri . '" label="Add"/>');
|
||||||
|
|
||||||
@ -112,30 +104,37 @@ class FacebookinviteAction extends FacebookAction
|
|||||||
|
|
||||||
$multi_params = array('showborder' => 'false');
|
$multi_params = array('showborder' => 'false');
|
||||||
$multi_params['actiontext'] = $actiontext;
|
$multi_params['actiontext'] = $actiontext;
|
||||||
|
$multi_params['bypass'] = 'cancel';
|
||||||
|
|
||||||
if ($exclude_ids_csv) {
|
// Get a list of users who are already using the app for exclusion
|
||||||
|
$exclude_ids = $this->facebook->api_client->friends_getAppUsers();
|
||||||
|
$exclude_ids_csv = null;
|
||||||
|
|
||||||
|
// fbml needs these as a csv string, not an array
|
||||||
|
if ($exclude_ids) {
|
||||||
|
$exclude_ids_csv = implode(',', $exclude_ids);
|
||||||
$multi_params['exclude_ids'] = $exclude_ids_csv;
|
$multi_params['exclude_ids'] = $exclude_ids_csv;
|
||||||
}
|
}
|
||||||
|
|
||||||
$multi_params['bypass'] = 'cancel';
|
|
||||||
|
|
||||||
$this->element('fb:multi-friend-selector', $multi_params);
|
$this->element('fb:multi-friend-selector', $multi_params);
|
||||||
|
|
||||||
$this->elementEnd('fb:request-form');
|
$this->elementEnd('fb:request-form');
|
||||||
|
|
||||||
$this->element('h2', null, sprintf(_('Friends already using %s:'),
|
if ($exclude_ids) {
|
||||||
common_config('site', 'name')));
|
|
||||||
$this->elementStart('ul', array('id' => 'facebook-friends'));
|
|
||||||
|
|
||||||
foreach ($exclude_ids as $friend) {
|
$this->element('h2', null, sprintf(_('Friends already using %s:'),
|
||||||
$this->elementStart('li');
|
common_config('site', 'name')));
|
||||||
$this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square'));
|
$this->elementStart('ul', array('id' => 'facebook-friends'));
|
||||||
$this->element('fb:name', array('uid' => $friend,
|
|
||||||
'capitalize' => 'true'));
|
foreach ($exclude_ids as $friend) {
|
||||||
$this->elementEnd('li');
|
$this->elementStart('li');
|
||||||
|
$this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square'));
|
||||||
|
$this->element('fb:name', array('uid' => $friend,
|
||||||
|
'capitalize' => 'true'));
|
||||||
|
$this->elementEnd('li');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementEnd("ul");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->elementEnd("ul");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
|
@ -55,7 +55,7 @@ class FacebooksettingsAction extends FacebookAction
|
|||||||
$prefix = $this->trimmed('prefix');
|
$prefix = $this->trimmed('prefix');
|
||||||
|
|
||||||
$original = clone($this->flink);
|
$original = clone($this->flink);
|
||||||
$this->flink->set_flags($noticesync, $replysync, false);
|
$this->flink->set_flags($noticesync, $replysync, false, false);
|
||||||
$result = $this->flink->update($original);
|
$result = $this->flink->update($original);
|
||||||
|
|
||||||
$this->facebook->api_client->data_setUserPreference(FACEBOOK_NOTICE_PREFIX,
|
$this->facebook->api_client->data_setUserPreference(FACEBOOK_NOTICE_PREFIX,
|
||||||
|
40
actions/file.php
Normal file
40
actions/file.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
|
require_once(INSTALLDIR.'/actions/shownotice.php');
|
||||||
|
|
||||||
|
class FileAction extends ShowNoticeAction
|
||||||
|
{
|
||||||
|
function showPage() {
|
||||||
|
$source_url = common_local_url('file', array('notice' => $this->notice->id));
|
||||||
|
$query = "select file_redirection.url as url from file join file_redirection on file.id = file_redirection.file_id where file.url = '$source_url'";
|
||||||
|
$file = new File_redirection;
|
||||||
|
$file->query($query);
|
||||||
|
$file->fetch();
|
||||||
|
if (empty($file->url)) {
|
||||||
|
die('nothing attached here');
|
||||||
|
} else {
|
||||||
|
header("Location: {$file->url}");
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -84,20 +84,24 @@ class NewnoticeAction extends Action
|
|||||||
|
|
||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
|
||||||
|
|
||||||
if (!common_logged_in()) {
|
if (!common_logged_in()) {
|
||||||
$this->clientError(_('Not logged in.'));
|
$this->clientError(_('Not logged in.'));
|
||||||
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
// check for this before token since all POST and FILES data
|
||||||
|
// is losts when size is exceeded
|
||||||
|
if (empty($_POST) && $_SERVER['CONTENT_LENGTH']) {
|
||||||
|
$this->clientError(sprintf(_('The server was unable to handle ' .
|
||||||
|
'that much POST data (%s bytes) due to its current configuration.'),
|
||||||
|
$_SERVER['CONTENT_LENGTH']));
|
||||||
|
}
|
||||||
|
parent::handle($args);
|
||||||
|
|
||||||
// CSRF protection
|
// CSRF protection
|
||||||
$token = $this->trimmed('token');
|
$token = $this->trimmed('token');
|
||||||
if (!$token || $token != common_session_token()) {
|
if (!$token || $token != common_session_token()) {
|
||||||
$this->clientError(_('There was a problem with your session token. '.
|
$this->clientError(_('There was a problem with your session token. '.
|
||||||
'Try again, please.'));
|
'Try again, please.'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->saveNewNotice();
|
$this->saveNewNotice();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
@ -109,6 +113,30 @@ class NewnoticeAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getUploadedFileType() {
|
||||||
|
require_once 'MIME/Type.php';
|
||||||
|
|
||||||
|
$filetype = MIME_Type::autoDetect($_FILES['attach']['tmp_name']);
|
||||||
|
if (in_array($filetype, common_config('attachments', 'supported'))) {
|
||||||
|
return $filetype;
|
||||||
|
}
|
||||||
|
$media = MIME_Type::getMedia($filetype);
|
||||||
|
if ('application' !== $media) {
|
||||||
|
$hint = sprintf(_(' Try using another %s format.'), $media);
|
||||||
|
} else {
|
||||||
|
$hint = '';
|
||||||
|
}
|
||||||
|
$this->clientError(sprintf(
|
||||||
|
_('%s is not a supported filetype on this server.'), $filetype) . $hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRespectsQuota($user) {
|
||||||
|
$file = new File;
|
||||||
|
$ret = $file->isRespectsQuota($user);
|
||||||
|
if (true === $ret) return true;
|
||||||
|
$this->clientError($ret);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a new notice, based on arguments
|
* Save a new notice, based on arguments
|
||||||
*
|
*
|
||||||
@ -131,7 +159,6 @@ class NewnoticeAction extends Action
|
|||||||
$this->clientError(_('No content!'));
|
$this->clientError(_('No content!'));
|
||||||
} else {
|
} else {
|
||||||
$content_shortened = common_shorten_links($content);
|
$content_shortened = common_shorten_links($content);
|
||||||
|
|
||||||
if (mb_strlen($content_shortened) > 140) {
|
if (mb_strlen($content_shortened) > 140) {
|
||||||
$this->clientError(_('That\'s too long. '.
|
$this->clientError(_('That\'s too long. '.
|
||||||
'Max notice size is 140 chars.'));
|
'Max notice size is 140 chars.'));
|
||||||
@ -158,17 +185,53 @@ class NewnoticeAction extends Action
|
|||||||
$replyto = 'false';
|
$replyto = 'false';
|
||||||
}
|
}
|
||||||
|
|
||||||
// $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
|
if (isset($_FILES['attach']['error'])) {
|
||||||
|
switch ($_FILES['attach']['error']) {
|
||||||
|
case UPLOAD_ERR_NO_FILE:
|
||||||
|
// no file uploaded, nothing to do
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UPLOAD_ERR_OK:
|
||||||
|
$mimetype = $this->getUploadedFileType();
|
||||||
|
if (!$this->isRespectsQuota($user)) {
|
||||||
|
die('clientError() should trigger an exception before reaching here.');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UPLOAD_ERR_INI_SIZE:
|
||||||
|
$this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.'));
|
||||||
|
|
||||||
|
case UPLOAD_ERR_FORM_SIZE:
|
||||||
|
$this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.'));
|
||||||
|
|
||||||
|
case UPLOAD_ERR_PARTIAL:
|
||||||
|
$this->clientError(_('The uploaded file was only partially uploaded.'));
|
||||||
|
|
||||||
|
case UPLOAD_ERR_NO_TMP_DIR:
|
||||||
|
$this->clientError(_('Missing a temporary folder.'));
|
||||||
|
|
||||||
|
case UPLOAD_ERR_CANT_WRITE:
|
||||||
|
$this->clientError(_('Failed to write file to disk.'));
|
||||||
|
|
||||||
|
case UPLOAD_ERR_EXTENSION:
|
||||||
|
$this->clientError(_('File upload stopped by extension.'));
|
||||||
|
|
||||||
|
default:
|
||||||
|
die('Should never reach here.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
|
$notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
|
||||||
($replyto == 'false') ? null : $replyto);
|
($replyto == 'false') ? null : $replyto);
|
||||||
|
|
||||||
if (is_string($notice)) {
|
if (is_string($notice)) {
|
||||||
$this->clientError($notice);
|
$this->clientError($notice);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($mimetype)) {
|
||||||
|
$this->storeFile($notice, $mimetype);
|
||||||
|
}
|
||||||
$this->saveUrls($notice);
|
$this->saveUrls($notice);
|
||||||
|
|
||||||
common_broadcast_notice($notice);
|
common_broadcast_notice($notice);
|
||||||
|
|
||||||
if ($this->boolean('ajax')) {
|
if ($this->boolean('ajax')) {
|
||||||
@ -194,6 +257,33 @@ class NewnoticeAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function storeFile($notice, $mimetype) {
|
||||||
|
$filename = basename($_FILES['attach']['name']);
|
||||||
|
$destination = "file/{$notice->id}-$filename";
|
||||||
|
if (move_uploaded_file($_FILES['attach']['tmp_name'], INSTALLDIR . "/$destination")) {
|
||||||
|
$file = new File;
|
||||||
|
$file->url = common_local_url('file', array('notice' => $notice->id));
|
||||||
|
$file->size = filesize(INSTALLDIR . "/$destination");
|
||||||
|
$file->date = time();
|
||||||
|
$file->mimetype = $mimetype;
|
||||||
|
if ($file_id = $file->insert()) {
|
||||||
|
$file_redir = new File_redirection;
|
||||||
|
$file_redir->url = common_path($destination);
|
||||||
|
$file_redir->file_id = $file_id;
|
||||||
|
$file_redir->insert();
|
||||||
|
|
||||||
|
$f2p = new File_to_post;
|
||||||
|
$f2p->file_id = $file_id;
|
||||||
|
$f2p->post_id = $notice->id;
|
||||||
|
$f2p->insert();
|
||||||
|
} else {
|
||||||
|
$this->clientError(_('There was a database error while saving your file. Please try again.'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->clientError(_('File could not be moved to destination directory.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** save all urls in the notice to the db
|
/** save all urls in the notice to the db
|
||||||
*
|
*
|
||||||
* follow redirects and save all available file information
|
* follow redirects and save all available file information
|
||||||
@ -203,7 +293,7 @@ class NewnoticeAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function saveUrls($notice) {
|
function saveUrls($notice, $uploaded = null) {
|
||||||
common_replace_urls_callback($notice->content, array($this, 'saveUrl'), $notice->id);
|
common_replace_urls_callback($notice->content, array($this, 'saveUrl'), $notice->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,3 +406,4 @@ class NewnoticeAction extends Action
|
|||||||
$nli->show();
|
$nli->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ class ShownoticeAction extends Action
|
|||||||
|
|
||||||
function lastModified()
|
function lastModified()
|
||||||
{
|
{
|
||||||
return max(strtotime($this->notice->created),
|
return max(strtotime($this->notice->modified),
|
||||||
strtotime($this->profile->modified),
|
strtotime($this->profile->modified),
|
||||||
($this->avatar) ? strtotime($this->avatar->modified) : 0);
|
($this->avatar) ? strtotime($this->avatar->modified) : 0);
|
||||||
}
|
}
|
||||||
@ -208,10 +208,10 @@ class ShownoticeAction extends Action
|
|||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$this->elementStart('ul', array('class' => 'notices'));
|
$this->elementStart('ol', array('class' => 'notices xoxo'));
|
||||||
$nli = new NoticeListItem($this->notice, $this);
|
$nli = new NoticeListItem($this->notice, $this);
|
||||||
$nli->show();
|
$nli->show();
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ol');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,9 +98,31 @@ class TwitapiaccountAction extends TwitterapiAction
|
|||||||
$this->serverError(_('API method under construction.'), $code=501);
|
$this->serverError(_('API method under construction.'), $code=501);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't have a rate limit, but some clients check this method.
|
||||||
|
// It always returns the same thing: 100 hit left.
|
||||||
function rate_limit_status($args, $apidata)
|
function rate_limit_status($args, $apidata)
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
$this->serverError(_('API method under construction.'), $code=501);
|
|
||||||
|
$type = $apidata['content-type'];
|
||||||
|
$this->init_document($type);
|
||||||
|
|
||||||
|
if ($apidata['content-type'] == 'xml') {
|
||||||
|
$this->elementStart('hash');
|
||||||
|
$this->element('remaining-hits', array('type' => 'integer'), 100);
|
||||||
|
$this->element('hourly-limit', array('type' => 'integer'), 100);
|
||||||
|
$this->element('reset-time', array('type' => 'datetime'), null);
|
||||||
|
$this->element('reset_time_in_seconds', array('type' => 'integer'), 0);
|
||||||
|
$this->elementEnd('hash');
|
||||||
|
} elseif ($apidata['content-type'] == 'json') {
|
||||||
|
|
||||||
|
$out = array('reset_time_in_seconds' => 0,
|
||||||
|
'remaining_hits' => 100,
|
||||||
|
'hourly_limit' => 100,
|
||||||
|
'reset_time' => '');
|
||||||
|
print json_encode($out);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->end_document($type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ class Twitapidirect_messagesAction extends TwitterapiAction
|
|||||||
$count = $this->arg('count');
|
$count = $this->arg('count');
|
||||||
$since = $this->arg('since');
|
$since = $this->arg('since');
|
||||||
$since_id = $this->arg('since_id');
|
$since_id = $this->arg('since_id');
|
||||||
$before_id = $this->arg('before_id');
|
$max_id = $this->arg('max_id');
|
||||||
|
|
||||||
$page = $this->arg('page');
|
$page = $this->arg('page');
|
||||||
|
|
||||||
@ -74,8 +74,8 @@ class Twitapidirect_messagesAction extends TwitterapiAction
|
|||||||
$link = $server . $user->nickname . '/outbox';
|
$link = $server . $user->nickname . '/outbox';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($before_id) {
|
if ($max_id) {
|
||||||
$message->whereAdd("id < $before_id");
|
$message->whereAdd("id <= $max_id");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($since_id) {
|
if ($since_id) {
|
||||||
|
@ -45,22 +45,21 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
|
|
||||||
$page = $this->arg('page');
|
$page = $this->arg('page');
|
||||||
$since_id = $this->arg('since_id');
|
$since_id = $this->arg('since_id');
|
||||||
$before_id = $this->arg('before_id');
|
$max_id = $this->arg('max_id');
|
||||||
|
|
||||||
// NOTE: page, since_id, and before_id are extensions to Twitter API -- TB
|
|
||||||
if (!$page) {
|
if (!$page) {
|
||||||
$page = 1;
|
$page = 1;
|
||||||
}
|
}
|
||||||
if (!$since_id) {
|
if (!$since_id) {
|
||||||
$since_id = 0;
|
$since_id = 0;
|
||||||
}
|
}
|
||||||
if (!$before_id) {
|
if (!$max_id) {
|
||||||
$before_id = 0;
|
$max_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$since = strtotime($this->arg('since'));
|
$since = strtotime($this->arg('since'));
|
||||||
|
|
||||||
$notice = Notice::publicStream((($page-1)*$MAX_PUBSTATUSES), $MAX_PUBSTATUSES, $since_id, $before_id, $since);
|
$notice = Notice::publicStream((($page-1)*$MAX_PUBSTATUSES), $MAX_PUBSTATUSES, $since_id, $max_id, $since);
|
||||||
|
|
||||||
if ($notice) {
|
if ($notice) {
|
||||||
|
|
||||||
@ -97,7 +96,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
$since_id = $this->arg('since_id');
|
$since_id = $this->arg('since_id');
|
||||||
$count = $this->arg('count');
|
$count = $this->arg('count');
|
||||||
$page = $this->arg('page');
|
$page = $this->arg('page');
|
||||||
$before_id = $this->arg('before_id');
|
$max_id = $this->arg('max_id');
|
||||||
|
|
||||||
if (!$page) {
|
if (!$page) {
|
||||||
$page = 1;
|
$page = 1;
|
||||||
@ -111,9 +110,8 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
$since_id = 0;
|
$since_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: before_id is an extension to Twitter API -- TB
|
if (!$max_id) {
|
||||||
if (!$before_id) {
|
$max_id = 0;
|
||||||
$before_id = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$since = strtotime($this->arg('since'));
|
$since = strtotime($this->arg('since'));
|
||||||
@ -133,7 +131,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
$link = common_local_url('all', array('nickname' => $user->nickname));
|
$link = common_local_url('all', array('nickname' => $user->nickname));
|
||||||
$subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), $user->nickname, $sitename);
|
$subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), $user->nickname, $sitename);
|
||||||
|
|
||||||
$notice = $user->noticesWithFriends(($page-1)*20, $count, $since_id, $before_id, $since);
|
$notice = $user->noticesWithFriends(($page-1)*20, $count, $since_id, $max_id, $since);
|
||||||
|
|
||||||
switch($apidata['content-type']) {
|
switch($apidata['content-type']) {
|
||||||
case 'xml':
|
case 'xml':
|
||||||
@ -184,7 +182,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
$since = $this->arg('since');
|
$since = $this->arg('since');
|
||||||
$since_id = $this->arg('since_id');
|
$since_id = $this->arg('since_id');
|
||||||
$page = $this->arg('page');
|
$page = $this->arg('page');
|
||||||
$before_id = $this->arg('before_id');
|
$max_id = $this->arg('max_id');
|
||||||
|
|
||||||
if (!$page) {
|
if (!$page) {
|
||||||
$page = 1;
|
$page = 1;
|
||||||
@ -198,9 +196,8 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
$since_id = 0;
|
$since_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: before_id is an extensions to Twitter API -- TB
|
if (!$max_id) {
|
||||||
if (!$before_id) {
|
$max_id = 0;
|
||||||
$before_id = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$since = strtotime($this->arg('since'));
|
$since = strtotime($this->arg('since'));
|
||||||
@ -220,7 +217,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
|
|
||||||
# XXX: since
|
# XXX: since
|
||||||
|
|
||||||
$notice = $user->getNotices((($page-1)*20), $count, $since_id, $before_id, $since);
|
$notice = $user->getNotices((($page-1)*20), $count, $since_id, $max_id, $since);
|
||||||
|
|
||||||
switch($apidata['content-type']) {
|
switch($apidata['content-type']) {
|
||||||
case 'xml':
|
case 'xml':
|
||||||
@ -353,7 +350,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
$count = $this->arg('count');
|
$count = $this->arg('count');
|
||||||
$page = $this->arg('page');
|
$page = $this->arg('page');
|
||||||
$since_id = $this->arg('since_id');
|
$since_id = $this->arg('since_id');
|
||||||
$before_id = $this->arg('before_id');
|
$max_id = $this->arg('max_id');
|
||||||
|
|
||||||
$user = $this->get_user($apidata['api_arg'], $apidata);
|
$user = $this->get_user($apidata['api_arg'], $apidata);
|
||||||
$this->auth_user = $apidata['user'];
|
$this->auth_user = $apidata['user'];
|
||||||
@ -380,15 +377,14 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
$since_id = 0;
|
$since_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: before_id is an extension to Twitter API -- TB
|
if (!$max_id) {
|
||||||
if (!$before_id) {
|
$max_id = 0;
|
||||||
$before_id = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$since = strtotime($this->arg('since'));
|
$since = strtotime($this->arg('since'));
|
||||||
|
|
||||||
$notice = $user->getReplies((($page-1)*20),
|
$notice = $user->getReplies((($page-1)*20),
|
||||||
$count, $since_id, $before_id, $since);
|
$count, $since_id, $max_id, $since);
|
||||||
$notices = array();
|
$notices = array();
|
||||||
|
|
||||||
while ($notice->fetch()) {
|
while ($notice->fetch()) {
|
||||||
|
@ -33,102 +33,53 @@ class TwitapiusersAction extends TwitterapiAction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = null;
|
$user = null;
|
||||||
$email = $this->arg('email');
|
$email = $this->arg('email');
|
||||||
$user_id = $this->arg('user_id');
|
$user_id = $this->arg('user_id');
|
||||||
|
|
||||||
if ($email) {
|
// XXX: email field deprecated in Twitter's API
|
||||||
$user = User::staticGet('email', $email);
|
|
||||||
} elseif ($user_id) {
|
|
||||||
$user = $this->get_user($user_id);
|
|
||||||
} elseif (isset($apidata['api_arg'])) {
|
|
||||||
$user = $this->get_user($apidata['api_arg']);
|
|
||||||
} elseif (isset($apidata['user'])) {
|
|
||||||
$user = $apidata['user'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$user) {
|
// XXX: Also: need to add screen_name param
|
||||||
// XXX: Twitter returns a random(?) user instead of throwing and err! -- Zach
|
|
||||||
$this->client_error(_('Not found.'), 404, $apidata['content-type']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$profile = $user->getProfile();
|
if ($email) {
|
||||||
|
$user = User::staticGet('email', $email);
|
||||||
|
} elseif ($user_id) {
|
||||||
|
$user = $this->get_user($user_id);
|
||||||
|
} elseif (isset($apidata['api_arg'])) {
|
||||||
|
$user = $this->get_user($apidata['api_arg']);
|
||||||
|
} elseif (isset($apidata['user'])) {
|
||||||
|
$user = $apidata['user'];
|
||||||
|
}
|
||||||
|
|
||||||
if (!$profile) {
|
if (!$user) {
|
||||||
common_server_error(_('User has no profile.'));
|
$this->client_error(_('Not found.'), 404, $apidata['content-type']);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$twitter_user = $this->twitter_user_array($profile, true);
|
$profile = $user->getProfile();
|
||||||
|
|
||||||
// Add in extended user fields offered up by this method
|
if (!$profile) {
|
||||||
$twitter_user['created_at'] = $this->date_twitter($profile->created);
|
common_server_error(_('User has no profile.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$subbed = DB_DataObject::factory('subscription');
|
$twitter_user = $this->twitter_user_array($profile, true);
|
||||||
$subbed->subscriber = $profile->id;
|
|
||||||
$subbed_count = (int) $subbed->count() - 1;
|
|
||||||
|
|
||||||
$notices = DB_DataObject::factory('notice');
|
if ($apidata['content-type'] == 'xml') {
|
||||||
$notices->profile_id = $profile->id;
|
$this->init_document('xml');
|
||||||
$notice_count = (int) $notices->count();
|
$this->show_twitter_xml_user($twitter_user);
|
||||||
|
$this->end_document('xml');
|
||||||
|
} elseif ($apidata['content-type'] == 'json') {
|
||||||
|
$this->init_document('json');
|
||||||
|
$this->show_json_objects($twitter_user);
|
||||||
|
$this->end_document('json');
|
||||||
|
} else {
|
||||||
|
|
||||||
$twitter_user['friends_count'] = (is_int($subbed_count)) ? $subbed_count : 0;
|
// This is in case 'show' was called via /account/verify_credentials
|
||||||
$twitter_user['statuses_count'] = (is_int($notice_count)) ? $notice_count : 0;
|
// without a format (xml or json).
|
||||||
|
|
||||||
// Other fields Twitter sends...
|
|
||||||
$twitter_user['profile_background_color'] = '';
|
|
||||||
$twitter_user['profile_background_image_url'] = '';
|
|
||||||
$twitter_user['profile_text_color'] = '';
|
|
||||||
$twitter_user['profile_link_color'] = '';
|
|
||||||
$twitter_user['profile_sidebar_fill_color'] = '';
|
|
||||||
$twitter_user['profile_sidebar_border_color'] = '';
|
|
||||||
$twitter_user['profile_background_tile'] = false;
|
|
||||||
|
|
||||||
$faves = DB_DataObject::factory('fave');
|
|
||||||
$faves->user_id = $user->id;
|
|
||||||
$faves_count = (int) $faves->count();
|
|
||||||
$twitter_user['favourites_count'] = $faves_count;
|
|
||||||
|
|
||||||
$timezone = 'UTC';
|
|
||||||
|
|
||||||
if ($user->timezone) {
|
|
||||||
$timezone = $user->timezone;
|
|
||||||
}
|
|
||||||
|
|
||||||
$t = new DateTime;
|
|
||||||
$t->setTimezone(new DateTimeZone($timezone));
|
|
||||||
$twitter_user['utc_offset'] = $t->format('Z');
|
|
||||||
$twitter_user['time_zone'] = $timezone;
|
|
||||||
|
|
||||||
if (isset($apidata['user'])) {
|
|
||||||
|
|
||||||
$twitter_user['following'] = $apidata['user']->isSubscribed($profile);
|
|
||||||
|
|
||||||
// Notifications on?
|
|
||||||
$sub = Subscription::pkeyGet(array('subscriber' =>
|
|
||||||
$apidata['user']->id, 'subscribed' => $profile->id));
|
|
||||||
|
|
||||||
if ($sub) {
|
|
||||||
$twitter_user['notifications'] = ($sub->jabber || $sub->sms);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($apidata['content-type'] == 'xml') {
|
|
||||||
$this->init_document('xml');
|
|
||||||
$this->show_twitter_xml_user($twitter_user);
|
|
||||||
$this->end_document('xml');
|
|
||||||
} elseif ($apidata['content-type'] == 'json') {
|
|
||||||
$this->init_document('json');
|
|
||||||
$this->show_json_objects($twitter_user);
|
|
||||||
$this->end_document('json');
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// This is in case 'show' was called via /account/verify_credentials
|
|
||||||
// without a format (xml or json).
|
|
||||||
header('Content-Type: text/html; charset=utf-8');
|
header('Content-Type: text/html; charset=utf-8');
|
||||||
print 'Authorized';
|
print 'Authorized';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ class Fave extends Memcached_DataObject
|
|||||||
return $ids;
|
return $ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _streamDirect($user_id, $offset, $limit, $since_id, $before_id, $since)
|
function _streamDirect($user_id, $offset, $limit, $since_id, $max_id, $since)
|
||||||
{
|
{
|
||||||
$fav = new Fave();
|
$fav = new Fave();
|
||||||
|
|
||||||
@ -59,8 +59,8 @@ class Fave extends Memcached_DataObject
|
|||||||
$fav->whereAdd('notice_id > ' . $since_id);
|
$fav->whereAdd('notice_id > ' . $since_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($before_id != 0) {
|
if ($max_id != 0) {
|
||||||
$fav->whereAdd('notice_id < ' . $before_id);
|
$fav->whereAdd('notice_id <= ' . $max_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($since)) {
|
if (!is_null($since)) {
|
||||||
|
@ -120,4 +120,30 @@ class File extends Memcached_DataObject
|
|||||||
File_to_post::processNew($file_id, $notice_id);
|
File_to_post::processNew($file_id, $notice_id);
|
||||||
return $x;
|
return $x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isRespectsQuota($user) {
|
||||||
|
if ($_FILES['attach']['size'] > common_config('attachments', 'file_quota')) {
|
||||||
|
return sprintf(_('No file may be larger than %d bytes ' .
|
||||||
|
'and the file you sent was %d bytes. Try to upload a smaller version.'),
|
||||||
|
common_config('attachments', 'file_quota'), $_FILES['attach']['size']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "select sum(size) as total from file join file_to_post on file_to_post.file_id = file.id join notice on file_to_post.post_id = notice.id where profile_id = {$user->id} and file.url like '%/notice/%/file'";
|
||||||
|
$this->query($query);
|
||||||
|
$this->fetch();
|
||||||
|
$total = $this->total + $_FILES['attach']['size'];
|
||||||
|
if ($total > common_config('attachments', 'user_quota')) {
|
||||||
|
return sprintf(_('A file this large would exceed your user quota of %d bytes.'), common_config('attachments', 'user_quota'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$query .= ' month(modified) = month(now()) and year(modified) = year(now())';
|
||||||
|
$this->query($query);
|
||||||
|
$this->fetch();
|
||||||
|
$total = $this->total + $_FILES['attach']['size'];
|
||||||
|
if ($total > common_config('attachments', 'monthly_quota')) {
|
||||||
|
return sprintf(_('A file this large would exceed your monthly quota of %d bytes.'), common_config('attachments', 'monthly_quota'));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ class File_redirection extends Memcached_DataObject
|
|||||||
$file->limit(1);
|
$file->limit(1);
|
||||||
$file->orderBy('len');
|
$file->orderBy('len');
|
||||||
$file->find(true);
|
$file->find(true);
|
||||||
if (!empty($file->id)) {
|
if (!empty($file->url) && (strlen($file->url) < strlen($long_url))) {
|
||||||
return $file->url;
|
return $file->url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ class Foreign_link extends Memcached_DataObject
|
|||||||
|
|
||||||
public $__table = 'foreign_link'; // table name
|
public $__table = 'foreign_link'; // table name
|
||||||
public $user_id; // int(4) primary_key not_null
|
public $user_id; // int(4) primary_key not_null
|
||||||
public $foreign_id; // int(4) primary_key not_null
|
public $foreign_id; // bigint(8) primary_key not_null unsigned
|
||||||
public $service; // int(4) primary_key not_null
|
public $service; // int(4) primary_key not_null
|
||||||
public $credentials; // varchar(255)
|
public $credentials; // varchar(255)
|
||||||
public $noticesync; // tinyint(1) not_null default_1
|
public $noticesync; // tinyint(1) not_null default_1
|
||||||
|
@ -227,4 +227,28 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
$c->set($ckey, $cached, MEMCACHE_COMPRESSED, $expiry);
|
$c->set($ckey, $cached, MEMCACHE_COMPRESSED, $expiry);
|
||||||
return new ArrayWrapper($cached);
|
return new ArrayWrapper($cached);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We overload so that 'SET NAMES "utf8"' is called for
|
||||||
|
// each connection
|
||||||
|
|
||||||
|
function _connect()
|
||||||
|
{
|
||||||
|
global $_DB_DATAOBJECT;
|
||||||
|
$exists = !empty($this->_database_dsn_md5) &&
|
||||||
|
isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]);
|
||||||
|
$result = parent::_connect();
|
||||||
|
if (!$exists) {
|
||||||
|
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
|
||||||
|
if (common_config('db', 'type') == 'mysql' &&
|
||||||
|
common_config('db', 'utf8')) {
|
||||||
|
$conn = $DB->connection;
|
||||||
|
if ($DB instanceof DB_mysqli) {
|
||||||
|
mysqli_set_charset($conn, 'utf8');
|
||||||
|
} else if ($DB instanceof DB_mysql) {
|
||||||
|
mysql_set_charset('utf8', $conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,8 @@ class Notice extends Memcached_DataObject
|
|||||||
|
|
||||||
$profile = Profile::staticGet($profile_id);
|
$profile = Profile::staticGet($profile_id);
|
||||||
|
|
||||||
|
$final = common_shorten_links($content);
|
||||||
|
|
||||||
if (!$profile) {
|
if (!$profile) {
|
||||||
common_log(LOG_ERR, 'Problem saving notice. Unknown user.');
|
common_log(LOG_ERR, 'Problem saving notice. Unknown user.');
|
||||||
return _('Problem saving notice. Unknown user.');
|
return _('Problem saving notice. Unknown user.');
|
||||||
@ -134,7 +136,7 @@ class Notice extends Memcached_DataObject
|
|||||||
return _('Too many notices too fast; take a breather and post again in a few minutes.');
|
return _('Too many notices too fast; take a breather and post again in a few minutes.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (common_config('site', 'dupelimit') > 0 && !Notice::checkDupes($profile_id, $content)) {
|
if (common_config('site', 'dupelimit') > 0 && !Notice::checkDupes($profile_id, $final)) {
|
||||||
common_log(LOG_WARNING, 'Dupe posting by profile #' . $profile_id . '; throttled.');
|
common_log(LOG_WARNING, 'Dupe posting by profile #' . $profile_id . '; throttled.');
|
||||||
return _('Too many duplicate messages too quickly; take a breather and post again in a few minutes.');
|
return _('Too many duplicate messages too quickly; take a breather and post again in a few minutes.');
|
||||||
}
|
}
|
||||||
@ -165,8 +167,8 @@ class Notice extends Memcached_DataObject
|
|||||||
|
|
||||||
$notice->reply_to = $reply_to;
|
$notice->reply_to = $reply_to;
|
||||||
$notice->created = common_sql_now();
|
$notice->created = common_sql_now();
|
||||||
$notice->content = $content;
|
$notice->content = $final;
|
||||||
$notice->rendered = common_render_content($content, $notice);
|
$notice->rendered = common_render_content($final, $notice);
|
||||||
$notice->source = $source;
|
$notice->source = $source;
|
||||||
$notice->uri = $uri;
|
$notice->uri = $uri;
|
||||||
|
|
||||||
@ -202,13 +204,9 @@ class Notice extends Memcached_DataObject
|
|||||||
|
|
||||||
$notice->saveReplies();
|
$notice->saveReplies();
|
||||||
$notice->saveTags();
|
$notice->saveTags();
|
||||||
$notice->saveGroups();
|
|
||||||
|
|
||||||
if (common_config('queue', 'enabled')) {
|
$notice->addToInboxes();
|
||||||
$notice->addToAuthorInbox();
|
$notice->saveGroups();
|
||||||
} else {
|
|
||||||
$notice->addToInboxes();
|
|
||||||
}
|
|
||||||
|
|
||||||
$notice->query('COMMIT');
|
$notice->query('COMMIT');
|
||||||
|
|
||||||
@ -218,13 +216,7 @@ class Notice extends Memcached_DataObject
|
|||||||
# Clear the cache for subscribed users, so they'll update at next request
|
# Clear the cache for subscribed users, so they'll update at next request
|
||||||
# XXX: someone clever could prepend instead of clearing the cache
|
# XXX: someone clever could prepend instead of clearing the cache
|
||||||
|
|
||||||
if (common_config('memcached', 'enabled')) {
|
$notice->blowCaches();
|
||||||
if (common_config('queue', 'enabled')) {
|
|
||||||
$notice->blowAuthorCaches();
|
|
||||||
} else {
|
|
||||||
$notice->blowCaches();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $notice;
|
return $notice;
|
||||||
}
|
}
|
||||||
@ -277,6 +269,18 @@ class Notice extends Memcached_DataObject
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getUploadedAttachment() {
|
||||||
|
$post = clone $this;
|
||||||
|
$query = 'select file.url as uploaded from file join file_to_post on file.id = file_id where post_id=' . $post->escape($post->id) . ' and url like "%/notice/%/file"';
|
||||||
|
$post->query($query);
|
||||||
|
$post->fetch();
|
||||||
|
$ret = $post->uploaded;
|
||||||
|
// var_dump($post);
|
||||||
|
$post->free();
|
||||||
|
// die();
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
function hasAttachments() {
|
function hasAttachments() {
|
||||||
$post = clone $this;
|
$post = clone $this;
|
||||||
$query = "select count(file_id) as n_attachments from file join file_to_post on (file_id = file.id) join notice on (post_id = notice.id) where post_id = " . $post->escape($post->id);
|
$query = "select count(file_id) as n_attachments from file join file_to_post on (file_id = file.id) join notice on (post_id = notice.id) where post_id = " . $post->escape($post->id);
|
||||||
@ -297,17 +301,6 @@ class Notice extends Memcached_DataObject
|
|||||||
$this->blowGroupCache($blowLast);
|
$this->blowGroupCache($blowLast);
|
||||||
}
|
}
|
||||||
|
|
||||||
function blowAuthorCaches($blowLast=false)
|
|
||||||
{
|
|
||||||
// Clear the user's cache
|
|
||||||
$cache = common_memcache();
|
|
||||||
if (!empty($cache)) {
|
|
||||||
$cache->delete(common_cache_key('notice_inbox:by_user:'.$this->profile_id));
|
|
||||||
}
|
|
||||||
$this->blowNoticeCache($blowLast);
|
|
||||||
$this->blowPublicCache($blowLast);
|
|
||||||
}
|
|
||||||
|
|
||||||
function blowGroupCache($blowLast=false)
|
function blowGroupCache($blowLast=false)
|
||||||
{
|
{
|
||||||
$cache = common_memcache();
|
$cache = common_memcache();
|
||||||
@ -443,22 +436,22 @@ class Notice extends Memcached_DataObject
|
|||||||
# XXX: too many args; we need to move to named params or even a separate
|
# XXX: too many args; we need to move to named params or even a separate
|
||||||
# class for notice streams
|
# class for notice streams
|
||||||
|
|
||||||
static function getStream($qry, $cachekey, $offset=0, $limit=20, $since_id=0, $before_id=0, $order=null, $since=null) {
|
static function getStream($qry, $cachekey, $offset=0, $limit=20, $since_id=0, $max_id=0, $order=null, $since=null) {
|
||||||
|
|
||||||
if (common_config('memcached', 'enabled')) {
|
if (common_config('memcached', 'enabled')) {
|
||||||
|
|
||||||
# Skip the cache if this is a since, since_id or before_id qry
|
# Skip the cache if this is a since, since_id or max_id qry
|
||||||
if ($since_id > 0 || $before_id > 0 || $since) {
|
if ($since_id > 0 || $max_id > 0 || $since) {
|
||||||
return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since);
|
return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since);
|
||||||
} else {
|
} else {
|
||||||
return Notice::getCachedStream($qry, $cachekey, $offset, $limit, $order);
|
return Notice::getCachedStream($qry, $cachekey, $offset, $limit, $order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since);
|
return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since) {
|
static function getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since) {
|
||||||
|
|
||||||
$needAnd = false;
|
$needAnd = false;
|
||||||
$needWhere = true;
|
$needWhere = true;
|
||||||
@ -480,7 +473,7 @@ class Notice extends Memcached_DataObject
|
|||||||
$qry .= ' notice.id > ' . $since_id;
|
$qry .= ' notice.id > ' . $since_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($before_id > 0) {
|
if ($max_id > 0) {
|
||||||
|
|
||||||
if ($needWhere) {
|
if ($needWhere) {
|
||||||
$qry .= ' WHERE ';
|
$qry .= ' WHERE ';
|
||||||
@ -489,7 +482,7 @@ class Notice extends Memcached_DataObject
|
|||||||
$qry .= ' AND ';
|
$qry .= ' AND ';
|
||||||
}
|
}
|
||||||
|
|
||||||
$qry .= ' notice.id < ' . $before_id;
|
$qry .= ' notice.id <= ' . $max_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($since) {
|
if ($since) {
|
||||||
@ -647,17 +640,17 @@ class Notice extends Memcached_DataObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function publicStream($offset=0, $limit=20, $since_id=0, $before_id=0, $since=null)
|
function publicStream($offset=0, $limit=20, $since_id=0, $max_id=0, $since=null)
|
||||||
{
|
{
|
||||||
$ids = Notice::stream(array('Notice', '_publicStreamDirect'),
|
$ids = Notice::stream(array('Notice', '_publicStreamDirect'),
|
||||||
array(),
|
array(),
|
||||||
'public',
|
'public',
|
||||||
$offset, $limit, $since_id, $before_id, $since);
|
$offset, $limit, $since_id, $max_id, $since);
|
||||||
|
|
||||||
return Notice::getStreamByIds($ids);
|
return Notice::getStreamByIds($ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _publicStreamDirect($offset=0, $limit=20, $since_id=0, $before_id=0, $since=null)
|
function _publicStreamDirect($offset=0, $limit=20, $since_id=0, $max_id=0, $since=null)
|
||||||
{
|
{
|
||||||
$notice = new Notice();
|
$notice = new Notice();
|
||||||
|
|
||||||
@ -681,8 +674,8 @@ class Notice extends Memcached_DataObject
|
|||||||
$notice->whereAdd('id > ' . $since_id);
|
$notice->whereAdd('id > ' . $since_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($before_id != 0) {
|
if ($max_id != 0) {
|
||||||
$notice->whereAdd('id < ' . $before_id);
|
$notice->whereAdd('id <= ' . $max_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($since)) {
|
if (!is_null($since)) {
|
||||||
@ -726,33 +719,6 @@ class Notice extends Memcached_DataObject
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToAuthorInbox()
|
|
||||||
{
|
|
||||||
$enabled = common_config('inboxes', 'enabled');
|
|
||||||
|
|
||||||
if ($enabled === true || $enabled === 'transitional') {
|
|
||||||
$user = User::staticGet('id', $this->profile_id);
|
|
||||||
if (empty($user)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$inbox = new Notice_inbox();
|
|
||||||
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
|
|
||||||
$qry = 'INSERT INTO notice_inbox (user_id, notice_id, created) ' .
|
|
||||||
"SELECT $UT.id, " . $this->id . ", '" . $this->created . "' " .
|
|
||||||
"FROM $UT " .
|
|
||||||
"WHERE $UT.id = " . $this->profile_id . ' ' .
|
|
||||||
'AND NOT EXISTS (SELECT user_id, notice_id ' .
|
|
||||||
'FROM notice_inbox ' .
|
|
||||||
"WHERE user_id = " . $this->profile_id . ' '.
|
|
||||||
'AND notice_id = ' . $this->id . ' )';
|
|
||||||
if ($enabled === 'transitional') {
|
|
||||||
$qry .= " AND $UT.inboxed = 1";
|
|
||||||
}
|
|
||||||
$inbox->query($qry);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveGroups()
|
function saveGroups()
|
||||||
{
|
{
|
||||||
$enabled = common_config('inboxes', 'enabled');
|
$enabled = common_config('inboxes', 'enabled');
|
||||||
@ -1024,15 +990,15 @@ class Notice extends Memcached_DataObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function stream($fn, $args, $cachekey, $offset=0, $limit=20, $since_id=0, $before_id=0, $since=null, $tag=null)
|
function stream($fn, $args, $cachekey, $offset=0, $limit=20, $since_id=0, $max_id=0, $since=null)
|
||||||
{
|
{
|
||||||
$cache = common_memcache();
|
$cache = common_memcache();
|
||||||
|
|
||||||
if (empty($cache) ||
|
if (empty($cache) ||
|
||||||
$since_id != 0 || $before_id != 0 || !is_null($since) ||
|
$since_id != 0 || $max_id != 0 || (!is_null($since) && $since > 0) ||
|
||||||
($offset + $limit) > NOTICE_CACHE_WINDOW) {
|
($offset + $limit) > NOTICE_CACHE_WINDOW) {
|
||||||
return call_user_func_array($fn, array_merge($args, array($offset, $limit, $since_id,
|
return call_user_func_array($fn, array_merge($args, array($offset, $limit, $since_id,
|
||||||
$before_id, $since, $tag)));
|
$max_id, $since)));
|
||||||
}
|
}
|
||||||
|
|
||||||
$idkey = common_cache_key($cachekey);
|
$idkey = common_cache_key($cachekey);
|
||||||
|
@ -43,15 +43,15 @@ class Notice_inbox extends Memcached_DataObject
|
|||||||
/* the code above is auto generated do not remove the tag below */
|
/* the code above is auto generated do not remove the tag below */
|
||||||
###END_AUTOCODE
|
###END_AUTOCODE
|
||||||
|
|
||||||
function stream($user_id, $offset, $limit, $since_id, $before_id, $since)
|
function stream($user_id, $offset, $limit, $since_id, $max_id, $since)
|
||||||
{
|
{
|
||||||
return Notice::stream(array('Notice_inbox', '_streamDirect'),
|
return Notice::stream(array('Notice_inbox', '_streamDirect'),
|
||||||
array($user_id),
|
array($user_id),
|
||||||
'notice_inbox:by_user:'.$user_id,
|
'notice_inbox:by_user:'.$user_id,
|
||||||
$offset, $limit, $since_id, $before_id, $since);
|
$offset, $limit, $since_id, $max_id, $since);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _streamDirect($user_id, $offset, $limit, $since_id, $before_id, $since)
|
function _streamDirect($user_id, $offset, $limit, $since_id, $max_id, $since)
|
||||||
{
|
{
|
||||||
$inbox = new Notice_inbox();
|
$inbox = new Notice_inbox();
|
||||||
|
|
||||||
@ -61,8 +61,8 @@ class Notice_inbox extends Memcached_DataObject
|
|||||||
$inbox->whereAdd('notice_id > ' . $since_id);
|
$inbox->whereAdd('notice_id > ' . $since_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($before_id != 0) {
|
if ($max_id != 0) {
|
||||||
$inbox->whereAdd('notice_id < ' . $before_id);
|
$inbox->whereAdd('notice_id <= ' . $max_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($since)) {
|
if (!is_null($since)) {
|
||||||
|
@ -46,7 +46,7 @@ class Notice_tag extends Memcached_DataObject
|
|||||||
return Notice::getStreamByIds($ids);
|
return Notice::getStreamByIds($ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _streamDirect($tag, $offset, $limit, $since_id, $before_id, $since)
|
function _streamDirect($tag, $offset, $limit, $since_id, $max_id, $since)
|
||||||
{
|
{
|
||||||
$nt = new Notice_tag();
|
$nt = new Notice_tag();
|
||||||
|
|
||||||
@ -59,8 +59,8 @@ class Notice_tag extends Memcached_DataObject
|
|||||||
$nt->whereAdd('notice_id > ' . $since_id);
|
$nt->whereAdd('notice_id > ' . $since_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($before_id != 0) {
|
if ($max_id != 0) {
|
||||||
$nt->whereAdd('notice_id < ' . $before_id);
|
$nt->whereAdd('notice_id < ' . $max_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($since)) {
|
if (!is_null($since)) {
|
||||||
|
@ -170,7 +170,7 @@ class Profile extends Memcached_DataObject
|
|||||||
$ids = Notice::stream(array($this, '_streamDirect'),
|
$ids = Notice::stream(array($this, '_streamDirect'),
|
||||||
array(),
|
array(),
|
||||||
'profile:notice_ids:' . $this->id,
|
'profile:notice_ids:' . $this->id,
|
||||||
$offset, $limit, $since_id, $before_id, $since);
|
$offset, $limit, $since_id, $max_id, $since);
|
||||||
|
|
||||||
return Notice::getStreamByIds($ids);
|
return Notice::getStreamByIds($ids);
|
||||||
}
|
}
|
||||||
@ -225,8 +225,8 @@ class Profile extends Memcached_DataObject
|
|||||||
$notice->whereAdd('id > ' . $since_id);
|
$notice->whereAdd('id > ' . $since_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($before_id != 0) {
|
if ($max_id != 0) {
|
||||||
$notice->whereAdd('id < ' . $before_id);
|
$notice->whereAdd('id <= ' . $max_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($since)) {
|
if (!is_null($since)) {
|
||||||
|
@ -22,16 +22,16 @@ class Reply extends Memcached_DataObject
|
|||||||
/* the code above is auto generated do not remove the tag below */
|
/* the code above is auto generated do not remove the tag below */
|
||||||
###END_AUTOCODE
|
###END_AUTOCODE
|
||||||
|
|
||||||
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null)
|
||||||
{
|
{
|
||||||
$ids = Notice::stream(array('Reply', '_streamDirect'),
|
$ids = Notice::stream(array('Reply', '_streamDirect'),
|
||||||
array($user_id),
|
array($user_id),
|
||||||
'reply:stream:' . $user_id,
|
'reply:stream:' . $user_id,
|
||||||
$offset, $limit, $since_id, $before_id, $since);
|
$offset, $limit, $since_id, $max_id, $since);
|
||||||
return $ids;
|
return $ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _streamDirect($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
function _streamDirect($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null)
|
||||||
{
|
{
|
||||||
$reply = new Reply();
|
$reply = new Reply();
|
||||||
$reply->profile_id = $user_id;
|
$reply->profile_id = $user_id;
|
||||||
@ -40,8 +40,8 @@ class Reply extends Memcached_DataObject
|
|||||||
$reply->whereAdd('notice_id > ' . $since_id);
|
$reply->whereAdd('notice_id > ' . $since_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($before_id != 0) {
|
if ($max_id != 0) {
|
||||||
$reply->whereAdd('notice_id < ' . $before_id);
|
$reply->whereAdd('notice_id < ' . $max_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($since)) {
|
if (!is_null($since)) {
|
||||||
|
@ -402,7 +402,6 @@ class User extends Memcached_DataObject
|
|||||||
function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||||
{
|
{
|
||||||
$ids = Reply::stream($this->id, $offset, $limit, $since_id, $before_id, $since);
|
$ids = Reply::stream($this->id, $offset, $limit, $since_id, $before_id, $since);
|
||||||
common_debug("Ids = " . implode(',', $ids));
|
|
||||||
return Notice::getStreamByIds($ids);
|
return Notice::getStreamByIds($ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class User_group extends Memcached_DataObject
|
|||||||
return Notice::getStreamByIds($ids);
|
return Notice::getStreamByIds($ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _streamDirect($offset, $limit, $since_id, $before_id, $since)
|
function _streamDirect($offset, $limit, $since_id, $max_id, $since)
|
||||||
{
|
{
|
||||||
$inbox = new Group_inbox();
|
$inbox = new Group_inbox();
|
||||||
|
|
||||||
@ -71,8 +71,8 @@ class User_group extends Memcached_DataObject
|
|||||||
$inbox->whereAdd('notice_id > ' . $since_id);
|
$inbox->whereAdd('notice_id > ' . $since_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($before_id != 0) {
|
if ($max_id != 0) {
|
||||||
$inbox->whereAdd('notice_id < ' . $before_id);
|
$inbox->whereAdd('notice_id <= ' . $max_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($since)) {
|
if (!is_null($since)) {
|
||||||
|
@ -215,3 +215,11 @@ $config['sphinx']['port'] = 3312;
|
|||||||
// $config['snapshot']['run'] = 'never';
|
// $config['snapshot']['run'] = 'never';
|
||||||
// If you want to report statistics in a cron job instead.
|
// If you want to report statistics in a cron job instead.
|
||||||
// $config['snapshot']['run'] = 'cron';
|
// $config['snapshot']['run'] = 'cron';
|
||||||
|
|
||||||
|
// Support for file uploads (attachments),
|
||||||
|
// select supported mimetypes and quotas (in bytes)
|
||||||
|
// $config['attachments']['supported'] = array('image/png', 'application/ogg');
|
||||||
|
// $config['attachments']['file_quota'] = 5000000;
|
||||||
|
// $config['attachments']['user_quota'] = 50000000;
|
||||||
|
// $config['attachments']['monthly_quota'] = 15000000;
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ create table foreign_user (
|
|||||||
|
|
||||||
create table foreign_link (
|
create table foreign_link (
|
||||||
user_id int comment 'link to user on this system, if exists' references user (id),
|
user_id int comment 'link to user on this system, if exists' references user (id),
|
||||||
foreign_id int comment 'link ' references foreign_user(id),
|
foreign_id bigint unsigned comment 'link to user on foreign service, if exists' references foreign_user(id),
|
||||||
service int not null comment 'foreign key to service' references foreign_service(id),
|
service int not null comment 'foreign key to service' references foreign_service(id),
|
||||||
credentials varchar(255) comment 'authc credentials, typically a password',
|
credentials varchar(255) comment 'authc credentials, typically a password',
|
||||||
noticesync tinyint not null default 1 comment 'notice synchronization, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies',
|
noticesync tinyint not null default 1 comment 'notice synchronization, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies',
|
||||||
|
@ -2,13 +2,18 @@ INSERT INTO notice_source
|
|||||||
(code, name, url, created)
|
(code, name, url, created)
|
||||||
VALUES
|
VALUES
|
||||||
('adium', 'Adium', 'http://www.adiumx.com/', now()),
|
('adium', 'Adium', 'http://www.adiumx.com/', now()),
|
||||||
|
('Afficheur', 'Afficheur', 'http://afficheur.sourceforge.jp/', now()),
|
||||||
|
('AgentSolo.com','AgentSolo.com','http://www.agentsolo.com/', now()),
|
||||||
|
('anyio', 'Any.IO', 'http://any.io/', now()),
|
||||||
('betwittered','BeTwittered','http://www.32hours.com/betwitteredinfo/', now()),
|
('betwittered','BeTwittered','http://www.32hours.com/betwitteredinfo/', now()),
|
||||||
('bti','bti','http://gregkh.github.com/bti/', now()),
|
('bti','bti','http://gregkh.github.com/bti/', now()),
|
||||||
('cliqset', 'Cliqset', 'http://www.cliqset.com/', now()),
|
('cliqset', 'Cliqset', 'http://www.cliqset.com/', now()),
|
||||||
('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()),
|
('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()),
|
||||||
('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()),
|
('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()),
|
||||||
|
('eventbox','EventBox','http://thecosmicmachine.com/eventbox/ ', now()),
|
||||||
('Facebook','Facebook','http://apps.facebook.com/identica/', now()),
|
('Facebook','Facebook','http://apps.facebook.com/identica/', now()),
|
||||||
('feed2omb','feed2omb','http://projects.ciarang.com/p/feed2omb/', now()),
|
('feed2omb','feed2omb','http://projects.ciarang.com/p/feed2omb/', now()),
|
||||||
|
('get2gnow', 'get2gnow', 'http://uberchicgeekchick.com/?projects=get2gnow', now()),
|
||||||
('gravity', 'Gravity', 'http://mobileways.de/gravity', now()),
|
('gravity', 'Gravity', 'http://mobileways.de/gravity', now()),
|
||||||
('Gwibber','Gwibber','http://launchpad.net/gwibber', now()),
|
('Gwibber','Gwibber','http://launchpad.net/gwibber', now()),
|
||||||
('HelloTxt','HelloTxt','http://hellotxt.com/', now()),
|
('HelloTxt','HelloTxt','http://hellotxt.com/', now()),
|
||||||
@ -28,6 +33,7 @@ VALUES
|
|||||||
('pingvine','PingVine','http://pingvine.com/', now()),
|
('pingvine','PingVine','http://pingvine.com/', now()),
|
||||||
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
||||||
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
||||||
|
('qtwitter','qTwitter','http://qtwitter.ayoy.net/', now()),
|
||||||
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
||||||
('rssdent','rssdent','http://github.com/zcopley/rssdent/tree/master', now()),
|
('rssdent','rssdent','http://github.com/zcopley/rssdent/tree/master', now()),
|
||||||
('rygh.no','rygh.no','http://rygh.no/', now()),
|
('rygh.no','rygh.no','http://rygh.no/', now()),
|
||||||
|
523
extlib/MIME/Type.php
Normal file
523
extlib/MIME/Type.php
Normal file
@ -0,0 +1,523 @@
|
|||||||
|
<?php
|
||||||
|
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | PHP version 4 |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 1997-2002, 2008 The PHP Group |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | This source file is subject to version 3.0 of the PHP license, |
|
||||||
|
// | that is bundled with this package in the file LICENSE, and is |
|
||||||
|
// | available at through the world-wide-web at |
|
||||||
|
// | http://www.php.net/license/3_0.txt. |
|
||||||
|
// | If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
// | obtain it through the world-wide-web, please send a note to |
|
||||||
|
// | license@php.net so we can mail you a copy immediately. |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Authors: Ian Eure <ieure@php.net> |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: Type.php,v 1.6 2009/01/16 11:49:45 cweiske Exp $
|
||||||
|
|
||||||
|
require_once 'PEAR.php';
|
||||||
|
|
||||||
|
$_fileCmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd');
|
||||||
|
$_fileCmd = 'file';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for working with MIME types
|
||||||
|
*
|
||||||
|
* @category MIME
|
||||||
|
* @package MIME_Type
|
||||||
|
* @license PHP License 3.0
|
||||||
|
* @version 1.2.0
|
||||||
|
* @link http://pear.php.net/package/MIME_Type
|
||||||
|
* @author Ian Eure <ieure@php.net>
|
||||||
|
*/
|
||||||
|
class MIME_Type
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The MIME media type
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $media = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MIME media sub-type
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $subType = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional MIME parameters
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
var $parameters = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of valid media types.
|
||||||
|
* A media type is the string in front of the slash.
|
||||||
|
* The media type of "text/xml" would be "text".
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
var $validMediaTypes = array(
|
||||||
|
'text',
|
||||||
|
'image',
|
||||||
|
'audio',
|
||||||
|
'video',
|
||||||
|
'application',
|
||||||
|
'multipart',
|
||||||
|
'message'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* If $type is set, if will be parsed and the appropriate class vars set.
|
||||||
|
* If not, you get an empty class.
|
||||||
|
* This is useful, but not quite as useful as parsing a type.
|
||||||
|
*
|
||||||
|
* @param string $type MIME type
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function MIME_Type($type = false)
|
||||||
|
{
|
||||||
|
if ($type) {
|
||||||
|
$this->parse($type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a mime-type and set the class variables.
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to parse
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function parse($type)
|
||||||
|
{
|
||||||
|
$this->media = $this->getMedia($type);
|
||||||
|
$this->subType = $this->getSubType($type);
|
||||||
|
$this->parameters = array();
|
||||||
|
if (MIME_Type::hasParameters($type)) {
|
||||||
|
require_once 'MIME/Type/Parameter.php';
|
||||||
|
foreach (MIME_Type::getParameters($type) as $param) {
|
||||||
|
$param = new MIME_Type_Parameter($param);
|
||||||
|
$this->parameters[$param->name] = $param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this type have any parameters?
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to check
|
||||||
|
*
|
||||||
|
* @return boolean true if $type has parameters, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function hasParameters($type)
|
||||||
|
{
|
||||||
|
if (strstr($type, ';')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a MIME type's parameters
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to get parameters of
|
||||||
|
*
|
||||||
|
* @return array $type's parameters
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getParameters($type)
|
||||||
|
{
|
||||||
|
$params = array();
|
||||||
|
$tmp = explode(';', $type);
|
||||||
|
for ($i = 1; $i < count($tmp); $i++) {
|
||||||
|
$params[] = trim($tmp[$i]);
|
||||||
|
}
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip parameters from a MIME type string.
|
||||||
|
*
|
||||||
|
* @param string $type MIME type string
|
||||||
|
*
|
||||||
|
* @return string MIME type with parameters removed
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function stripParameters($type)
|
||||||
|
{
|
||||||
|
if (strstr($type, ';')) {
|
||||||
|
return substr($type, 0, strpos($type, ';'));
|
||||||
|
}
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes comments from a media type, subtype or parameter.
|
||||||
|
*
|
||||||
|
* @param string $string String to strip comments from
|
||||||
|
* @param string &$comment Comment is stored in there.
|
||||||
|
*
|
||||||
|
* @return string String without comments
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function stripComments($string, &$comment)
|
||||||
|
{
|
||||||
|
if (strpos($string, '(') === false) {
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
$inquote = false;
|
||||||
|
$quoting = false;
|
||||||
|
$incomment = 0;
|
||||||
|
$newstring = '';
|
||||||
|
|
||||||
|
for ($n = 0; $n < strlen($string); $n++) {
|
||||||
|
if ($quoting) {
|
||||||
|
if ($incomment == 0) {
|
||||||
|
$newstring .= $string[$n];
|
||||||
|
} else if ($comment !== null) {
|
||||||
|
$comment .= $string[$n];
|
||||||
|
}
|
||||||
|
$quoting = false;
|
||||||
|
} else if ($string[$n] == '\\') {
|
||||||
|
$quoting = true;
|
||||||
|
} else if (!$inquote && $incomment > 0 && $string[$n] == ')') {
|
||||||
|
$incomment--;
|
||||||
|
if ($incomment == 0 && $comment !== null) {
|
||||||
|
$comment .= ' ';
|
||||||
|
}
|
||||||
|
} else if (!$inquote && $string[$n] == '(') {
|
||||||
|
$incomment++;
|
||||||
|
} else if ($string[$n] == '"') {
|
||||||
|
if ($inquote) {
|
||||||
|
$inquote = false;
|
||||||
|
} else {
|
||||||
|
$inquote = true;
|
||||||
|
}
|
||||||
|
} else if ($incomment == 0) {
|
||||||
|
$newstring .= $string[$n];
|
||||||
|
} else if ($comment !== null) {
|
||||||
|
$comment .= $string[$n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($comment !== null) {
|
||||||
|
$comment = trim($comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $newstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a MIME type's media
|
||||||
|
*
|
||||||
|
* @note 'media' refers to the portion before the first slash
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to get media of
|
||||||
|
*
|
||||||
|
* @return string $type's media
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getMedia($type)
|
||||||
|
{
|
||||||
|
$tmp = explode('/', $type);
|
||||||
|
return strtolower(trim(MIME_Type::stripComments($tmp[0], $null)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a MIME type's subtype
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to get subtype of
|
||||||
|
*
|
||||||
|
* @return string $type's subtype, null if invalid mime type
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getSubType($type)
|
||||||
|
{
|
||||||
|
$tmp = explode('/', $type);
|
||||||
|
if (!isset($tmp[1])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$tmp = explode(';', $tmp[1]);
|
||||||
|
return strtolower(trim(MIME_Type::stripComments($tmp[0], $null)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a textual MIME type from object values
|
||||||
|
*
|
||||||
|
* This function performs the opposite function of parse().
|
||||||
|
*
|
||||||
|
* @return string MIME type string
|
||||||
|
*/
|
||||||
|
function get()
|
||||||
|
{
|
||||||
|
$type = strtolower($this->media . '/' . $this->subType);
|
||||||
|
if (count($this->parameters)) {
|
||||||
|
foreach ($this->parameters as $key => $null) {
|
||||||
|
$type .= '; ' . $this->parameters[$key]->get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this type experimental?
|
||||||
|
*
|
||||||
|
* @note Experimental types are denoted by a leading 'x-' in the media or
|
||||||
|
* subtype, e.g. text/x-vcard or x-world/x-vrml.
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to check
|
||||||
|
*
|
||||||
|
* @return boolean true if $type is experimental, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function isExperimental($type)
|
||||||
|
{
|
||||||
|
if (substr(MIME_Type::getMedia($type), 0, 2) == 'x-' ||
|
||||||
|
substr(MIME_Type::getSubType($type), 0, 2) == 'x-') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a vendor MIME type?
|
||||||
|
*
|
||||||
|
* @note Vendor types are denoted with a leading 'vnd. in the subtype.
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to check
|
||||||
|
*
|
||||||
|
* @return boolean true if $type is a vendor type, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function isVendor($type)
|
||||||
|
{
|
||||||
|
if (substr(MIME_Type::getSubType($type), 0, 4) == 'vnd.') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a wildcard type?
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to check
|
||||||
|
*
|
||||||
|
* @return boolean true if $type is a wildcard, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function isWildcard($type)
|
||||||
|
{
|
||||||
|
if ($type == '*/*' || MIME_Type::getSubtype($type) == '*') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a wildcard match on a MIME type
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* MIME_Type::wildcardMatch('image/*', 'image/png')
|
||||||
|
*
|
||||||
|
* @param string $card Wildcard to check against
|
||||||
|
* @param string $type MIME type to check
|
||||||
|
*
|
||||||
|
* @return boolean true if there was a match, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function wildcardMatch($card, $type)
|
||||||
|
{
|
||||||
|
if (!MIME_Type::isWildcard($card)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($card == '*/*') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MIME_Type::getMedia($card) == MIME_Type::getMedia($type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a parameter to this type
|
||||||
|
*
|
||||||
|
* @param string $name Attribute name
|
||||||
|
* @param string $value Attribute value
|
||||||
|
* @param string $comment Comment for this parameter
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function addParameter($name, $value, $comment = false)
|
||||||
|
{
|
||||||
|
$tmp = new MIME_Type_Parameter();
|
||||||
|
|
||||||
|
$tmp->name = $name;
|
||||||
|
$tmp->value = $value;
|
||||||
|
$tmp->comment = $comment;
|
||||||
|
$this->parameters[$name] = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a parameter from this type
|
||||||
|
*
|
||||||
|
* @param string $name Parameter name
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function removeParameter($name)
|
||||||
|
{
|
||||||
|
unset($this->parameters[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autodetect a file's MIME-type
|
||||||
|
*
|
||||||
|
* This function may be called staticly.
|
||||||
|
*
|
||||||
|
* @internal Tries to use fileinfo extension at first. If that
|
||||||
|
* does not work, mime_magic is used. If this is also not available
|
||||||
|
* or does not succeed, "file" command is tried to be executed with
|
||||||
|
* System_Command. When that fails, too, then we use our in-built
|
||||||
|
* extension-to-mimetype-mapping list.
|
||||||
|
*
|
||||||
|
* @param string $file Path to the file to get the type of
|
||||||
|
* @param bool $params Append MIME parameters if true
|
||||||
|
*
|
||||||
|
* @return string $file's MIME-type on success, PEAR_Error otherwise
|
||||||
|
*
|
||||||
|
* @since 1.0.0beta1
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function autoDetect($file, $params = false)
|
||||||
|
{
|
||||||
|
// Sanity checks
|
||||||
|
if (!file_exists($file)) {
|
||||||
|
return PEAR::raiseError("File \"$file\" doesn't exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_readable($file)) {
|
||||||
|
return PEAR::raiseError("File \"$file\" is not readable");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('finfo_file')) {
|
||||||
|
$finfo = finfo_open(FILEINFO_MIME);
|
||||||
|
$type = finfo_file($finfo, $file);
|
||||||
|
finfo_close($finfo);
|
||||||
|
if ($type !== false && $type !== '') {
|
||||||
|
return MIME_Type::_handleDetection($type, $params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('mime_content_type')) {
|
||||||
|
$type = mime_content_type($file);
|
||||||
|
if ($type !== false && $type !== '') {
|
||||||
|
return MIME_Type::_handleDetection($type, $params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include_once 'System/Command.php';
|
||||||
|
if (class_exists('System_Command')) {
|
||||||
|
return MIME_Type::_handleDetection(
|
||||||
|
MIME_Type::_fileAutoDetect($file),
|
||||||
|
$params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once 'MIME/Type/Extension.php';
|
||||||
|
$mte = new MIME_Type_Extension();
|
||||||
|
return $mte->getMIMEType($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a detected MIME type and modifies it if necessary.
|
||||||
|
*
|
||||||
|
* @param string $type MIME Type of a file
|
||||||
|
* @param bool $params Append MIME parameters if true
|
||||||
|
*
|
||||||
|
* @return string $file's MIME-type on success, PEAR_Error otherwise
|
||||||
|
*/
|
||||||
|
function _handleDetection($type, $params)
|
||||||
|
{
|
||||||
|
// _fileAutoDetect() may have returned an error.
|
||||||
|
if (PEAR::isError($type)) {
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't return an empty string
|
||||||
|
if (!$type || !strlen($type)) {
|
||||||
|
return PEAR::raiseError("Sorry, couldn't determine file type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip parameters if present & requested
|
||||||
|
if (MIME_Type::hasParameters($type) && !$params) {
|
||||||
|
$type = MIME_Type::stripParameters($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autodetect a file's MIME-type with 'file' and System_Command
|
||||||
|
*
|
||||||
|
* This function may be called staticly.
|
||||||
|
*
|
||||||
|
* @param string $file Path to the file to get the type of
|
||||||
|
*
|
||||||
|
* @return string $file's MIME-type
|
||||||
|
*
|
||||||
|
* @since 1.0.0beta1
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function _fileAutoDetect($file)
|
||||||
|
{
|
||||||
|
$cmd = new System_Command();
|
||||||
|
|
||||||
|
// Make sure we have the 'file' command.
|
||||||
|
$fileCmd = PEAR::getStaticProperty('MIME_Type', 'fileCmd');
|
||||||
|
if (!$cmd->which($fileCmd)) {
|
||||||
|
unset($cmd);
|
||||||
|
return PEAR::raiseError("Can't find file command \"{$fileCmd}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
$cmd->pushCommand($fileCmd, "-bi " . escapeshellarg($file));
|
||||||
|
$res = $cmd->execute();
|
||||||
|
unset($cmd);
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
298
extlib/MIME/Type/Extension.php
Normal file
298
extlib/MIME/Type/Extension.php
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
<?php
|
||||||
|
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | PHP versions 4 and 5 |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 1997-2009 The PHP Group |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | This source file is subject to version 3.0 of the PHP license, |
|
||||||
|
// | that is bundled with this package in the file LICENSE, and is |
|
||||||
|
// | available at through the world-wide-web at |
|
||||||
|
// | http://www.php.net/license/3_0.txt. |
|
||||||
|
// | If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
// | obtain it through the world-wide-web, please send a note to |
|
||||||
|
// | license@php.net so we can mail you a copy immediately. |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Authors: Christian Schmidt <schmidt@php.net> |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: Extension.php,v 1.1 2009/01/16 11:49:45 cweiske Exp $
|
||||||
|
|
||||||
|
require_once 'PEAR.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for mapping file extensions to MIME types.
|
||||||
|
*
|
||||||
|
* @category MIME
|
||||||
|
* @package MIME_Type
|
||||||
|
* @author Christian Schmidt <schmidt@php.net>
|
||||||
|
* @license PHP License 3.0
|
||||||
|
* @version 1.2.0
|
||||||
|
* @link http://pear.php.net/package/MIME_Type
|
||||||
|
*/
|
||||||
|
class MIME_Type_Extension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Mapping between file extension and MIME type.
|
||||||
|
*
|
||||||
|
* @internal The array is sorted alphabetically by value and with primary
|
||||||
|
* extension first. Be careful about not adding duplicate keys - PHP
|
||||||
|
* silently ignores duplicates. The following command can be used for
|
||||||
|
* checking for duplicates:
|
||||||
|
* grep "=> '" Extension.php | cut -d\' -f2 | sort | uniq -d
|
||||||
|
* application/octet-stream is generally used as fallback when no other
|
||||||
|
* MIME-type can be found, but the array does not contain a lot of such
|
||||||
|
* unknown extension. One entry exists, though, to allow detection of
|
||||||
|
* file extension for this MIME-type.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
var $extensionToType = array (
|
||||||
|
'ez' => 'application/andrew-inset',
|
||||||
|
'atom' => 'application/atom+xml',
|
||||||
|
'jar' => 'application/java-archive',
|
||||||
|
'hqx' => 'application/mac-binhex40',
|
||||||
|
'cpt' => 'application/mac-compactpro',
|
||||||
|
'mathml' => 'application/mathml+xml',
|
||||||
|
'doc' => 'application/msword',
|
||||||
|
'dat' => 'application/octet-stream',
|
||||||
|
'oda' => 'application/oda',
|
||||||
|
'ogg' => 'application/ogg',
|
||||||
|
'pdf' => 'application/pdf',
|
||||||
|
'ai' => 'application/postscript',
|
||||||
|
'eps' => 'application/postscript',
|
||||||
|
'ps' => 'application/postscript',
|
||||||
|
'rdf' => 'application/rdf+xml',
|
||||||
|
'rss' => 'application/rss+xml',
|
||||||
|
'smi' => 'application/smil',
|
||||||
|
'smil' => 'application/smil',
|
||||||
|
'gram' => 'application/srgs',
|
||||||
|
'grxml' => 'application/srgs+xml',
|
||||||
|
'kml' => 'application/vnd.google-earth.kml+xml',
|
||||||
|
'kmz' => 'application/vnd.google-earth.kmz',
|
||||||
|
'mif' => 'application/vnd.mif',
|
||||||
|
'xul' => 'application/vnd.mozilla.xul+xml',
|
||||||
|
'xls' => 'application/vnd.ms-excel',
|
||||||
|
'xlb' => 'application/vnd.ms-excel',
|
||||||
|
'xlt' => 'application/vnd.ms-excel',
|
||||||
|
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
|
||||||
|
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
|
||||||
|
'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
|
||||||
|
'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
|
||||||
|
'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
|
||||||
|
'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
|
||||||
|
'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
|
||||||
|
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
|
||||||
|
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
|
||||||
|
'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
|
||||||
|
'ppt' => 'application/vnd.ms-powerpoint',
|
||||||
|
'pps' => 'application/vnd.ms-powerpoint',
|
||||||
|
'odc' => 'application/vnd.oasis.opendocument.chart',
|
||||||
|
'odb' => 'application/vnd.oasis.opendocument.database',
|
||||||
|
'odf' => 'application/vnd.oasis.opendocument.formula',
|
||||||
|
'odg' => 'application/vnd.oasis.opendocument.graphics',
|
||||||
|
'otg' => 'application/vnd.oasis.opendocument.graphics-template',
|
||||||
|
'odi' => 'application/vnd.oasis.opendocument.image',
|
||||||
|
'odp' => 'application/vnd.oasis.opendocument.presentation',
|
||||||
|
'otp' => 'application/vnd.oasis.opendocument.presentation-template',
|
||||||
|
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
||||||
|
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
|
||||||
|
'odt' => 'application/vnd.oasis.opendocument.text',
|
||||||
|
'odm' => 'application/vnd.oasis.opendocument.text-master',
|
||||||
|
'ott' => 'application/vnd.oasis.opendocument.text-template',
|
||||||
|
'oth' => 'application/vnd.oasis.opendocument.text-web',
|
||||||
|
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
|
||||||
|
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
|
||||||
|
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||||
|
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
|
||||||
|
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||||
|
'vsd' => 'application/vnd.visio',
|
||||||
|
'wbxml' => 'application/vnd.wap.wbxml',
|
||||||
|
'wmlc' => 'application/vnd.wap.wmlc',
|
||||||
|
'wmlsc' => 'application/vnd.wap.wmlscriptc',
|
||||||
|
'vxml' => 'application/voicexml+xml',
|
||||||
|
'bcpio' => 'application/x-bcpio',
|
||||||
|
'vcd' => 'application/x-cdlink',
|
||||||
|
'pgn' => 'application/x-chess-pgn',
|
||||||
|
'cpio' => 'application/x-cpio',
|
||||||
|
'csh' => 'application/x-csh',
|
||||||
|
'dcr' => 'application/x-director',
|
||||||
|
'dir' => 'application/x-director',
|
||||||
|
'dxr' => 'application/x-director',
|
||||||
|
'dvi' => 'application/x-dvi',
|
||||||
|
'spl' => 'application/x-futuresplash',
|
||||||
|
'tgz' => 'application/x-gtar',
|
||||||
|
'gtar' => 'application/x-gtar',
|
||||||
|
'hdf' => 'application/x-hdf',
|
||||||
|
'js' => 'application/x-javascript',
|
||||||
|
'skp' => 'application/x-koan',
|
||||||
|
'skd' => 'application/x-koan',
|
||||||
|
'skt' => 'application/x-koan',
|
||||||
|
'skm' => 'application/x-koan',
|
||||||
|
'latex' => 'application/x-latex',
|
||||||
|
'nc' => 'application/x-netcdf',
|
||||||
|
'cdf' => 'application/x-netcdf',
|
||||||
|
'sh' => 'application/x-sh',
|
||||||
|
'shar' => 'application/x-shar',
|
||||||
|
'swf' => 'application/x-shockwave-flash',
|
||||||
|
'sit' => 'application/x-stuffit',
|
||||||
|
'sv4cpio' => 'application/x-sv4cpio',
|
||||||
|
'sv4crc' => 'application/x-sv4crc',
|
||||||
|
'tar' => 'application/x-tar',
|
||||||
|
'tcl' => 'application/x-tcl',
|
||||||
|
'tex' => 'application/x-tex',
|
||||||
|
'texinfo' => 'application/x-texinfo',
|
||||||
|
'texi' => 'application/x-texinfo',
|
||||||
|
't' => 'application/x-troff',
|
||||||
|
'tr' => 'application/x-troff',
|
||||||
|
'roff' => 'application/x-troff',
|
||||||
|
'man' => 'application/x-troff-man',
|
||||||
|
'me' => 'application/x-troff-me',
|
||||||
|
'ms' => 'application/x-troff-ms',
|
||||||
|
'ustar' => 'application/x-ustar',
|
||||||
|
'src' => 'application/x-wais-source',
|
||||||
|
'xhtml' => 'application/xhtml+xml',
|
||||||
|
'xht' => 'application/xhtml+xml',
|
||||||
|
'xslt' => 'application/xslt+xml',
|
||||||
|
'xml' => 'application/xml',
|
||||||
|
'xsl' => 'application/xml',
|
||||||
|
'dtd' => 'application/xml-dtd',
|
||||||
|
'zip' => 'application/zip',
|
||||||
|
'au' => 'audio/basic',
|
||||||
|
'snd' => 'audio/basic',
|
||||||
|
'mid' => 'audio/midi',
|
||||||
|
'midi' => 'audio/midi',
|
||||||
|
'kar' => 'audio/midi',
|
||||||
|
'mpga' => 'audio/mpeg',
|
||||||
|
'mp2' => 'audio/mpeg',
|
||||||
|
'mp3' => 'audio/mpeg',
|
||||||
|
'aif' => 'audio/x-aiff',
|
||||||
|
'aiff' => 'audio/x-aiff',
|
||||||
|
'aifc' => 'audio/x-aiff',
|
||||||
|
'm3u' => 'audio/x-mpegurl',
|
||||||
|
'wma' => 'audio/x-ms-wma',
|
||||||
|
'wax' => 'audio/x-ms-wax',
|
||||||
|
'ram' => 'audio/x-pn-realaudio',
|
||||||
|
'ra' => 'audio/x-pn-realaudio',
|
||||||
|
'rm' => 'application/vnd.rn-realmedia',
|
||||||
|
'wav' => 'audio/x-wav',
|
||||||
|
'pdb' => 'chemical/x-pdb',
|
||||||
|
'xyz' => 'chemical/x-xyz',
|
||||||
|
'bmp' => 'image/bmp',
|
||||||
|
'cgm' => 'image/cgm',
|
||||||
|
'gif' => 'image/gif',
|
||||||
|
'ief' => 'image/ief',
|
||||||
|
'jpeg' => 'image/jpeg',
|
||||||
|
'jpg' => 'image/jpeg',
|
||||||
|
'jpe' => 'image/jpeg',
|
||||||
|
'png' => 'image/png',
|
||||||
|
'svg' => 'image/svg+xml',
|
||||||
|
'tiff' => 'image/tiff',
|
||||||
|
'tif' => 'image/tiff',
|
||||||
|
'djvu' => 'image/vnd.djvu',
|
||||||
|
'djv' => 'image/vnd.djvu',
|
||||||
|
'wbmp' => 'image/vnd.wap.wbmp',
|
||||||
|
'ras' => 'image/x-cmu-raster',
|
||||||
|
'ico' => 'image/x-icon',
|
||||||
|
'pnm' => 'image/x-portable-anymap',
|
||||||
|
'pbm' => 'image/x-portable-bitmap',
|
||||||
|
'pgm' => 'image/x-portable-graymap',
|
||||||
|
'ppm' => 'image/x-portable-pixmap',
|
||||||
|
'rgb' => 'image/x-rgb',
|
||||||
|
'xbm' => 'image/x-xbitmap',
|
||||||
|
'psd' => 'image/x-photoshop',
|
||||||
|
'xpm' => 'image/x-xpixmap',
|
||||||
|
'xwd' => 'image/x-xwindowdump',
|
||||||
|
'eml' => 'message/rfc822',
|
||||||
|
'igs' => 'model/iges',
|
||||||
|
'iges' => 'model/iges',
|
||||||
|
'msh' => 'model/mesh',
|
||||||
|
'mesh' => 'model/mesh',
|
||||||
|
'silo' => 'model/mesh',
|
||||||
|
'wrl' => 'model/vrml',
|
||||||
|
'vrml' => 'model/vrml',
|
||||||
|
'ics' => 'text/calendar',
|
||||||
|
'ifb' => 'text/calendar',
|
||||||
|
'css' => 'text/css',
|
||||||
|
'csv' => 'text/csv',
|
||||||
|
'html' => 'text/html',
|
||||||
|
'htm' => 'text/html',
|
||||||
|
'txt' => 'text/plain',
|
||||||
|
'asc' => 'text/plain',
|
||||||
|
'rtx' => 'text/richtext',
|
||||||
|
'rtf' => 'text/rtf',
|
||||||
|
'sgml' => 'text/sgml',
|
||||||
|
'sgm' => 'text/sgml',
|
||||||
|
'tsv' => 'text/tab-separated-values',
|
||||||
|
'wml' => 'text/vnd.wap.wml',
|
||||||
|
'wmls' => 'text/vnd.wap.wmlscript',
|
||||||
|
'etx' => 'text/x-setext',
|
||||||
|
'mpeg' => 'video/mpeg',
|
||||||
|
'mpg' => 'video/mpeg',
|
||||||
|
'mpe' => 'video/mpeg',
|
||||||
|
'qt' => 'video/quicktime',
|
||||||
|
'mov' => 'video/quicktime',
|
||||||
|
'mxu' => 'video/vnd.mpegurl',
|
||||||
|
'm4u' => 'video/vnd.mpegurl',
|
||||||
|
'flv' => 'video/x-flv',
|
||||||
|
'asf' => 'video/x-ms-asf',
|
||||||
|
'asx' => 'video/x-ms-asf',
|
||||||
|
'wmv' => 'video/x-ms-wmv',
|
||||||
|
'wm' => 'video/x-ms-wm',
|
||||||
|
'wmx' => 'video/x-ms-wmx',
|
||||||
|
'avi' => 'video/x-msvideo',
|
||||||
|
'ogv' => 'video/ogg',
|
||||||
|
'movie' => 'video/x-sgi-movie',
|
||||||
|
'ice' => 'x-conference/x-cooltalk',
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autodetect a file's MIME-type.
|
||||||
|
*
|
||||||
|
* @param string $file Path to the file to get the type of
|
||||||
|
*
|
||||||
|
* @return string $file's MIME-type on success, PEAR_Error otherwise
|
||||||
|
*/
|
||||||
|
function getMIMEType($file)
|
||||||
|
{
|
||||||
|
$extension = substr(strrchr($file, '.'), 1);
|
||||||
|
if ($extension === false) {
|
||||||
|
return PEAR::raiseError("File has no extension.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->extensionToType[$extension])) {
|
||||||
|
return PEAR::raiseError("Sorry, couldn't determine file type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->extensionToType[$extension];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return default MIME-type for the specified extension.
|
||||||
|
*
|
||||||
|
* @param string $type MIME-type
|
||||||
|
*
|
||||||
|
* @return string A file extension without leading period.
|
||||||
|
*/
|
||||||
|
function getExtension($type)
|
||||||
|
{
|
||||||
|
require_once 'MIME/Type.php';
|
||||||
|
// Strip parameters and comments.
|
||||||
|
$type = MIME_Type::getMedia($type) . '/' . MIME_Type::getSubType($type);
|
||||||
|
|
||||||
|
$extension = array_search($type, $this->extensionToType);
|
||||||
|
if ($extension === false) {
|
||||||
|
return PEAR::raiseError("Sorry, couldn't determine extension.");
|
||||||
|
}
|
||||||
|
return $extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
163
extlib/MIME/Type/Parameter.php
Normal file
163
extlib/MIME/Type/Parameter.php
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
<?php
|
||||||
|
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | PHP version 4 |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 1997-2002 The PHP Group |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | This source file is subject to version 3.0 of the PHP license, |
|
||||||
|
// | that is bundled with this package in the file LICENSE, and is |
|
||||||
|
// | available at through the world-wide-web at |
|
||||||
|
// | http://www.php.net/license/3_0.txt. |
|
||||||
|
// | If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
// | obtain it through the world-wide-web, please send a note to |
|
||||||
|
// | license@php.net so we can mail you a copy immediately. |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Authors: Ian Eure <ieure@php.net> |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: Parameter.php,v 1.1 2007/03/25 10:10:21 cweiske Exp $
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for working with MIME type parameters
|
||||||
|
*
|
||||||
|
* @version 1.2.0
|
||||||
|
* @package MIME_Type
|
||||||
|
* @author Ian Eure <ieure@php.net>
|
||||||
|
*/
|
||||||
|
class MIME_Type_Parameter {
|
||||||
|
/**
|
||||||
|
* Parameter name
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameter value
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameter comment
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $comment;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param string $param MIME parameter to parse, if set.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function MIME_Type_Parameter($param = false)
|
||||||
|
{
|
||||||
|
if ($param) {
|
||||||
|
$this->parse($param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a MIME type parameter and set object fields
|
||||||
|
*
|
||||||
|
* @param string $param MIME type parameter to parse
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function parse($param)
|
||||||
|
{
|
||||||
|
$comment = '';
|
||||||
|
$param = MIME_Type::stripComments($param, $comment);
|
||||||
|
$this->name = $this->getAttribute($param);
|
||||||
|
$this->value = $this->getValue($param);
|
||||||
|
$this->comment = $comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a parameter attribute (e.g. name)
|
||||||
|
*
|
||||||
|
* @param string MIME type parameter
|
||||||
|
* @return string Attribute name
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getAttribute($param)
|
||||||
|
{
|
||||||
|
$tmp = explode('=', $param);
|
||||||
|
return trim($tmp[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a parameter value
|
||||||
|
*
|
||||||
|
* @param string $param MIME type parameter
|
||||||
|
* @return string Value
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getValue($param)
|
||||||
|
{
|
||||||
|
$tmp = explode('=', $param, 2);
|
||||||
|
$value = $tmp[1];
|
||||||
|
$value = trim($value);
|
||||||
|
if ($value[0] == '"' && $value[strlen($value)-1] == '"') {
|
||||||
|
$value = substr($value, 1, -1);
|
||||||
|
}
|
||||||
|
$value = str_replace('\\"', '"', $value);
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a parameter comment
|
||||||
|
*
|
||||||
|
* @param string $param MIME type parameter
|
||||||
|
* @return string Parameter comment
|
||||||
|
* @see getComment()
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getComment($param)
|
||||||
|
{
|
||||||
|
$cs = strpos($param, '(');
|
||||||
|
$comment = substr($param, $cs);
|
||||||
|
return trim($comment, '() ');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this parameter have a comment?
|
||||||
|
*
|
||||||
|
* @param string $param MIME type parameter
|
||||||
|
* @return boolean true if $param has a comment, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function hasComment($param)
|
||||||
|
{
|
||||||
|
if (strstr($param, '(')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a string representation of this parameter
|
||||||
|
*
|
||||||
|
* This function performs the oppsite of parse()
|
||||||
|
*
|
||||||
|
* @return string String representation of parameter
|
||||||
|
*/
|
||||||
|
function get()
|
||||||
|
{
|
||||||
|
$val = $this->name . '="' . str_replace('"', '\\"', $this->value) . '"';
|
||||||
|
if ($this->comment) {
|
||||||
|
$val .= ' (' . $this->comment . ')';
|
||||||
|
}
|
||||||
|
return $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -157,7 +157,7 @@ $.fn.ajaxSubmit = function(options) {
|
|||||||
function fileUpload() {
|
function fileUpload() {
|
||||||
var form = $form[0];
|
var form = $form[0];
|
||||||
|
|
||||||
if ($(':input[@name=submit]', form).length) {
|
if ($(':input[name=submit]', form).length) {
|
||||||
alert('Error: Form elements must not be named "submit".');
|
alert('Error: Form elements must not be named "submit".');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -570,7 +570,7 @@ $.fn.clearForm = function() {
|
|||||||
$.fn.clearFields = $.fn.clearInputs = function() {
|
$.fn.clearFields = $.fn.clearInputs = function() {
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
var t = this.type, tag = this.tagName.toLowerCase();
|
var t = this.type, tag = this.tagName.toLowerCase();
|
||||||
if (t == 'text' || t == 'password' || tag == 'textarea')
|
if (t == 'file' || t == 'text' || t == 'password' || tag == 'textarea')
|
||||||
this.value = '';
|
this.value = '';
|
||||||
else if (t == 'checkbox' || t == 'radio')
|
else if (t == 'checkbox' || t == 'radio')
|
||||||
this.checked = false;
|
this.checked = false;
|
||||||
|
76
js/util.js
76
js/util.js
@ -17,30 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
$('a.attachment').click(function() {$().jOverlay({url: $('address .url')[0].href+'/attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'}); return false; });
|
|
||||||
$("a.thumbnail").hover(
|
|
||||||
function() {
|
|
||||||
var anchor = $(this);
|
|
||||||
$("a.thumbnail").children('img').remove();
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
anchor.closest(".entry-title").addClass('ov');
|
|
||||||
$.get($('address .url')[0].href+'/attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) {
|
|
||||||
anchor.append(data);
|
|
||||||
});
|
|
||||||
}, 250);
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
anchor.children('img').remove();
|
|
||||||
anchor.closest(".entry-title").removeClass('ov');
|
|
||||||
}, 3000);
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
$(this).children('img').remove();
|
|
||||||
$(this).closest(".entry-title").removeClass('ov');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// count character on keyup
|
// count character on keyup
|
||||||
function counter(event){
|
function counter(event){
|
||||||
var maxLength = 140;
|
var maxLength = 140;
|
||||||
@ -227,6 +203,7 @@ $(document).ready(function(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$("#notice_data-text").val("");
|
$("#notice_data-text").val("");
|
||||||
|
$("#notice_data-attach").val("");
|
||||||
counter();
|
counter();
|
||||||
}
|
}
|
||||||
$("#form_notice").removeClass("processing");
|
$("#form_notice").removeClass("processing");
|
||||||
@ -238,6 +215,7 @@ $(document).ready(function(){
|
|||||||
$("#form_notice").each(addAjaxHidden);
|
$("#form_notice").each(addAjaxHidden);
|
||||||
NoticeHover();
|
NoticeHover();
|
||||||
NoticeReply();
|
NoticeReply();
|
||||||
|
NoticeAttachments();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -276,3 +254,53 @@ function NoticeReplySet(nick,id) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function NoticeAttachments() {
|
||||||
|
$.fn.jOverlay.options = {
|
||||||
|
method : 'GET',
|
||||||
|
data : '',
|
||||||
|
url : '',
|
||||||
|
color : '#000',
|
||||||
|
opacity : '0.6',
|
||||||
|
zIndex : 99,
|
||||||
|
center : true,
|
||||||
|
imgLoading : $('address .url')[0].href+'theme/base/images/illustrations/illu_progress_loading-01.gif',
|
||||||
|
bgClickToClose : true,
|
||||||
|
success : function() {
|
||||||
|
$('#jOverlayContent').append('<button>×</button>');
|
||||||
|
$('#jOverlayContent button').click($.closeOverlay);
|
||||||
|
},
|
||||||
|
timeout : 0
|
||||||
|
};
|
||||||
|
|
||||||
|
$('a.attachment').click(function() {
|
||||||
|
$().jOverlay({url: $('address .url')[0].href+'/attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
var t;
|
||||||
|
$("body:not(#shownotice) a.thumbnail").hover(
|
||||||
|
function() {
|
||||||
|
var anchor = $(this);
|
||||||
|
$("a.thumbnail").children('img').hide();
|
||||||
|
anchor.closest(".entry-title").addClass('ov');
|
||||||
|
|
||||||
|
if (anchor.children('img').length == 0) {
|
||||||
|
t = setTimeout(function() {
|
||||||
|
$.get($('address .url')[0].href+'/attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) {
|
||||||
|
anchor.append(data);
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
anchor.children('img').show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
clearTimeout(t);
|
||||||
|
$("a.thumbnail").children('img').hide();
|
||||||
|
$(this).closest(".entry-title").removeClass('ov');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -79,20 +79,21 @@ class AttachmentList extends Widget
|
|||||||
|
|
||||||
function show()
|
function show()
|
||||||
{
|
{
|
||||||
$this->out->elementStart('dl', array('id' =>'attachment'));
|
|
||||||
$this->out->element('dt', null, _('Attachments'));
|
|
||||||
$this->out->elementStart('dd');
|
|
||||||
$this->out->elementStart('ul', array('class' => 'attachments'));
|
|
||||||
|
|
||||||
$atts = new File;
|
$atts = new File;
|
||||||
$att = $atts->getAttachments($this->notice->id);
|
$att = $atts->getAttachments($this->notice->id);
|
||||||
|
if (empty($att)) return 0;
|
||||||
|
$this->out->elementStart('dl', array('id' =>'attachments'));
|
||||||
|
$this->out->element('dt', null, _('Attachments'));
|
||||||
|
$this->out->elementStart('dd');
|
||||||
|
$this->out->elementStart('ol', array('class' => 'attachments'));
|
||||||
|
|
||||||
foreach ($att as $n=>$attachment) {
|
foreach ($att as $n=>$attachment) {
|
||||||
$item = $this->newListItem($attachment);
|
$item = $this->newListItem($attachment);
|
||||||
$item->show();
|
$item->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('dd');
|
$this->out->elementEnd('dd');
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ol');
|
||||||
$this->out->elementEnd('dl');
|
$this->out->elementEnd('dl');
|
||||||
|
|
||||||
return count($att);
|
return count($att);
|
||||||
@ -266,6 +267,23 @@ class Attachment extends AttachmentListItem
|
|||||||
case 'image/jpeg':
|
case 'image/jpeg':
|
||||||
$this->out->element('img', array('src' => $this->attachment->url, 'alt' => 'alt'));
|
$this->out->element('img', array('src' => $this->attachment->url, 'alt' => 'alt'));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'application/ogg':
|
||||||
|
case 'audio/x-speex':
|
||||||
|
case 'video/mpeg':
|
||||||
|
case 'audio/mpeg':
|
||||||
|
case 'video/mp4':
|
||||||
|
case 'video/quicktime':
|
||||||
|
$arr = array('type' => $this->attachment->mimetype,
|
||||||
|
'data' => $this->attachment->url,
|
||||||
|
'width' => 320,
|
||||||
|
'height' => 240
|
||||||
|
);
|
||||||
|
$this->out->elementStart('object', $arr);
|
||||||
|
$this->out->element('param', array('name' => 'src', 'value' => $this->attachment->url));
|
||||||
|
$this->out->element('param', array('name' => 'autoStart', 'value' => 1));
|
||||||
|
$this->out->elementEnd('object');
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -163,6 +163,42 @@ $config =
|
|||||||
array('run' => 'web',
|
array('run' => 'web',
|
||||||
'frequency' => 10000,
|
'frequency' => 10000,
|
||||||
'reporturl' => 'http://laconi.ca/stats/report'),
|
'reporturl' => 'http://laconi.ca/stats/report'),
|
||||||
|
'attachments' =>
|
||||||
|
array('supported' => array('image/png',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/gif',
|
||||||
|
'image/svg+xml',
|
||||||
|
'audio/mpeg',
|
||||||
|
'audio/x-speex',
|
||||||
|
'application/ogg',
|
||||||
|
'application/pdf',
|
||||||
|
'application/vnd.oasis.opendocument.text',
|
||||||
|
'application/vnd.oasis.opendocument.text-template',
|
||||||
|
'application/vnd.oasis.opendocument.graphics',
|
||||||
|
'application/vnd.oasis.opendocument.graphics-template',
|
||||||
|
'application/vnd.oasis.opendocument.presentation',
|
||||||
|
'application/vnd.oasis.opendocument.presentation-template',
|
||||||
|
'application/vnd.oasis.opendocument.spreadsheet',
|
||||||
|
'application/vnd.oasis.opendocument.spreadsheet-template',
|
||||||
|
'application/vnd.oasis.opendocument.chart',
|
||||||
|
'application/vnd.oasis.opendocument.chart-template',
|
||||||
|
'application/vnd.oasis.opendocument.image',
|
||||||
|
'application/vnd.oasis.opendocument.image-template',
|
||||||
|
'application/vnd.oasis.opendocument.formula',
|
||||||
|
'application/vnd.oasis.opendocument.formula-template',
|
||||||
|
'application/vnd.oasis.opendocument.text-master',
|
||||||
|
'application/vnd.oasis.opendocument.text-web',
|
||||||
|
'application/x-zip',
|
||||||
|
'application/zip',
|
||||||
|
'text/plain',
|
||||||
|
'video/mpeg',
|
||||||
|
'video/mp4',
|
||||||
|
'video/quicktime',
|
||||||
|
'video/mpeg'),
|
||||||
|
'file_quota' => 5000000,
|
||||||
|
'user_quota' => 50000000,
|
||||||
|
'monthly_quota' => 15000000,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
|
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
|
||||||
@ -174,6 +210,7 @@ $config['db'] =
|
|||||||
'require_prefix' => 'classes/',
|
'require_prefix' => 'classes/',
|
||||||
'class_prefix' => '',
|
'class_prefix' => '',
|
||||||
'mirror' => null,
|
'mirror' => null,
|
||||||
|
'utf8' => true,
|
||||||
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
|
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
|
||||||
'quote_identifiers' => false,
|
'quote_identifiers' => false,
|
||||||
'type' => 'mysql' );
|
'type' => 'mysql' );
|
||||||
@ -223,19 +260,19 @@ if ($_db_name != 'laconica' && !array_key_exists('ini_'.$_db_name, $config['db']
|
|||||||
|
|
||||||
// XXX: how many of these could be auto-loaded on use?
|
// XXX: how many of these could be auto-loaded on use?
|
||||||
|
|
||||||
require_once('Validate.php');
|
require_once 'Validate.php';
|
||||||
require_once('markdown.php');
|
require_once 'markdown.php';
|
||||||
|
|
||||||
require_once(INSTALLDIR.'/lib/util.php');
|
require_once INSTALLDIR.'/lib/util.php';
|
||||||
require_once(INSTALLDIR.'/lib/action.php');
|
require_once INSTALLDIR.'/lib/action.php';
|
||||||
require_once(INSTALLDIR.'/lib/theme.php');
|
require_once INSTALLDIR.'/lib/theme.php';
|
||||||
require_once(INSTALLDIR.'/lib/mail.php');
|
require_once INSTALLDIR.'/lib/mail.php';
|
||||||
require_once(INSTALLDIR.'/lib/subs.php');
|
require_once INSTALLDIR.'/lib/subs.php';
|
||||||
require_once(INSTALLDIR.'/lib/Shorturl_api.php');
|
require_once INSTALLDIR.'/lib/Shorturl_api.php';
|
||||||
require_once(INSTALLDIR.'/lib/twitter.php');
|
require_once INSTALLDIR.'/lib/twitter.php';
|
||||||
|
|
||||||
require_once(INSTALLDIR.'/lib/clientexception.php');
|
require_once INSTALLDIR.'/lib/clientexception.php';
|
||||||
require_once(INSTALLDIR.'/lib/serverexception.php');
|
require_once INSTALLDIR.'/lib/serverexception.php';
|
||||||
|
|
||||||
// XXX: other formats here
|
// XXX: other formats here
|
||||||
|
|
||||||
|
@ -98,9 +98,9 @@ class FacebookAction extends Action
|
|||||||
// Add a timestamp to the file so Facebook cache wont ignore our changes
|
// Add a timestamp to the file so Facebook cache wont ignore our changes
|
||||||
$ts = filemtime(INSTALLDIR.'/theme/base/css/display.css');
|
$ts = filemtime(INSTALLDIR.'/theme/base/css/display.css');
|
||||||
|
|
||||||
$this->element('link', array('rel' => 'stylesheet',
|
$this->element('link', array('rel' => 'stylesheet',
|
||||||
'type' => 'text/css',
|
'type' => 'text/css',
|
||||||
'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts));
|
'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts));
|
||||||
|
|
||||||
$theme = common_config('site', 'theme');
|
$theme = common_config('site', 'theme');
|
||||||
|
|
||||||
@ -278,7 +278,7 @@ class FacebookAction extends Action
|
|||||||
$this->element('a',
|
$this->element('a',
|
||||||
array('href' => common_local_url('register')), _('Register'));
|
array('href' => common_local_url('register')), _('Register'));
|
||||||
$this->text($loginmsg_part2);
|
$this->text($loginmsg_part2);
|
||||||
$this->elementEnd('p');
|
$this->elementEnd('p');
|
||||||
$this->elementEnd('dd');
|
$this->elementEnd('dd');
|
||||||
|
|
||||||
$this->elementEnd('dl');
|
$this->elementEnd('dl');
|
||||||
@ -317,7 +317,7 @@ class FacebookAction extends Action
|
|||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
$this->submit('submit', _('Login'));
|
$this->submit('submit', _('Login'));
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
|
|
||||||
$this->elementStart('p');
|
$this->elementStart('p');
|
||||||
@ -336,65 +336,65 @@ class FacebookAction extends Action
|
|||||||
|
|
||||||
// Need to include inline CSS for styling the Profile box
|
// Need to include inline CSS for styling the Profile box
|
||||||
|
|
||||||
$app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url'));
|
$app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url'));
|
||||||
$icon_url = $app_props['icon_url'];
|
$icon_url = $app_props['icon_url'];
|
||||||
|
|
||||||
$style = '<style>
|
$style = '<style>
|
||||||
.entry-title *,
|
.entry-title *,
|
||||||
.entry-content * {
|
.entry-content * {
|
||||||
font-size:14px;
|
font-size:14px;
|
||||||
font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||||
}
|
}
|
||||||
.entry-title a,
|
.entry-title a,
|
||||||
.entry-content a {
|
.entry-content a {
|
||||||
color:#002E6E;
|
color:#002E6E;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry-title .vcard .photo {
|
.entry-title .vcard .photo {
|
||||||
float:left;
|
float:left;
|
||||||
display:inline;
|
display:inline;
|
||||||
margin-right:11px;
|
margin-right:11px;
|
||||||
margin-bottom:11px
|
margin-bottom:11px
|
||||||
}
|
}
|
||||||
.entry-title {
|
.entry-title {
|
||||||
margin-bottom:11px;
|
margin-bottom:11px;
|
||||||
}
|
}
|
||||||
.entry-title p.entry-content {
|
.entry-title p.entry-content {
|
||||||
display:inline;
|
display:inline;
|
||||||
margin-left:5px;
|
margin-left:5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.entry-content {
|
div.entry-content {
|
||||||
clear:both;
|
clear:both;
|
||||||
}
|
}
|
||||||
div.entry-content dl,
|
div.entry-content dl,
|
||||||
div.entry-content dt,
|
div.entry-content dt,
|
||||||
div.entry-content dd {
|
div.entry-content dd {
|
||||||
display:inline;
|
display:inline;
|
||||||
text-transform:lowercase;
|
text-transform:lowercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.entry-content dd,
|
div.entry-content dd,
|
||||||
div.entry-content .device dt {
|
div.entry-content .device dt {
|
||||||
margin-left:0;
|
margin-left:0;
|
||||||
margin-right:5px;
|
margin-right:5px;
|
||||||
}
|
}
|
||||||
div.entry-content dl.timestamp dt,
|
div.entry-content dl.timestamp dt,
|
||||||
div.entry-content dl.response dt {
|
div.entry-content dl.response dt {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
div.entry-content dd a {
|
div.entry-content dd a {
|
||||||
display:inline-block;
|
display:inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
#facebook_laconica_app {
|
#facebook_laconica_app {
|
||||||
text-indent:-9999px;
|
text-indent:-9999px;
|
||||||
height:16px;
|
height:16px;
|
||||||
width:16px;
|
width:16px;
|
||||||
display:block;
|
display:block;
|
||||||
background:url('.$icon_url.') no-repeat 0 0;
|
background:url('.$icon_url.') no-repeat 0 0;
|
||||||
float:right;
|
float:right;
|
||||||
}
|
}
|
||||||
</style>';
|
</style>';
|
||||||
|
|
||||||
$this->xw->openMemory();
|
$this->xw->openMemory();
|
||||||
@ -646,48 +646,16 @@ class FacebookNoticeListItem extends NoticeListItem
|
|||||||
function show()
|
function show()
|
||||||
{
|
{
|
||||||
$this->showStart();
|
$this->showStart();
|
||||||
|
$this->showNotice();
|
||||||
|
$this->showNoticeInfo();
|
||||||
|
|
||||||
$this->out->elementStart('div', 'entry-title');
|
// XXX: Need to update to show attachements and controls
|
||||||
$this->showAuthor();
|
|
||||||
$this->showContent();
|
|
||||||
$this->out->elementEnd('div');
|
|
||||||
|
|
||||||
$this->out->elementStart('div', 'entry-content');
|
|
||||||
$this->showNoticeLink();
|
|
||||||
$this->showNoticeSource();
|
|
||||||
$this->showReplyTo();
|
|
||||||
$this->out->elementEnd('div');
|
|
||||||
|
|
||||||
$this->showEnd();
|
$this->showEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showNoticeLink()
|
|
||||||
{
|
|
||||||
$noticeurl = common_local_url('shownotice',
|
|
||||||
array('notice' => $this->notice->id));
|
|
||||||
// XXX: we need to figure this out better. Is this right?
|
|
||||||
if (strcmp($this->notice->uri, $noticeurl) != 0 &&
|
|
||||||
preg_match('/^http/', $this->notice->uri)) {
|
|
||||||
$noticeurl = $this->notice->uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->out->elementStart('dl', 'timestamp');
|
|
||||||
$this->out->element('dt', null, _('Published'));
|
|
||||||
$this->out->elementStart('dd', null);
|
|
||||||
$this->out->elementStart('a', array('rel' => 'bookmark',
|
|
||||||
'href' => $noticeurl));
|
|
||||||
$dt = common_date_iso8601($this->notice->created);
|
|
||||||
$this->out->element('abbr', array('class' => 'published',
|
|
||||||
'title' => $dt),
|
|
||||||
common_date_string($this->notice->created));
|
|
||||||
$this->out->elementEnd('a');
|
|
||||||
$this->out->elementEnd('dd');
|
|
||||||
$this->out->elementEnd('dl');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class FacebookProfileBoxNotice extends FacebookNoticeListItem
|
class FacebookProfileBoxNotice extends FacebookNoticeListItem
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -706,28 +674,16 @@ class FacebookProfileBoxNotice extends FacebookNoticeListItem
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Recipe function for displaying a single notice in the
|
* Recipe function for displaying a single notice in the
|
||||||
* Facebook App's Profile
|
* Facebook App profile notice box
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function show()
|
function show()
|
||||||
{
|
{
|
||||||
|
$this->showNotice();
|
||||||
$this->out->elementStart('div', 'entry-title');
|
$this->showNoticeInfo();
|
||||||
$this->showAuthor();
|
|
||||||
$this->showContent();
|
|
||||||
$this->out->elementEnd('div');
|
|
||||||
|
|
||||||
$this->out->elementStart('div', 'entry-content');
|
|
||||||
|
|
||||||
$this->showNoticeLink();
|
|
||||||
$this->showNoticeSource();
|
|
||||||
$this->showReplyTo();
|
|
||||||
$this->out->elementEnd('div');
|
|
||||||
|
|
||||||
$this->showAppLink();
|
$this->showAppLink();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAppLink()
|
function showAppLink()
|
||||||
|
16
lib/form.php
16
lib/form.php
@ -52,6 +52,8 @@ require_once INSTALLDIR.'/lib/widget.php';
|
|||||||
|
|
||||||
class Form extends Widget
|
class Form extends Widget
|
||||||
{
|
{
|
||||||
|
var $enctype = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the form
|
* Show the form
|
||||||
*
|
*
|
||||||
@ -63,11 +65,15 @@ class Form extends Widget
|
|||||||
|
|
||||||
function show()
|
function show()
|
||||||
{
|
{
|
||||||
$this->out->elementStart('form',
|
$attributes = array('id' => $this->id(),
|
||||||
array('id' => $this->id(),
|
'class' => $this->formClass(),
|
||||||
'class' => $this->formClass(),
|
'method' => 'post',
|
||||||
'method' => 'post',
|
'action' => $this->action());
|
||||||
'action' => $this->action()));
|
|
||||||
|
if (!empty($this->enctype)) {
|
||||||
|
$attributes['enctype'] = $this->enctype;
|
||||||
|
}
|
||||||
|
$this->out->elementStart('form', $attributes);
|
||||||
$this->out->elementStart('fieldset');
|
$this->out->elementStart('fieldset');
|
||||||
$this->formLegend();
|
$this->formLegend();
|
||||||
$this->sessionToken();
|
$this->sessionToken();
|
||||||
|
@ -335,6 +335,7 @@ function mail_broadcast_notice_sms($notice)
|
|||||||
"FROM $UT JOIN subscription " .
|
"FROM $UT JOIN subscription " .
|
||||||
"ON $UT.id = subscription.subscriber " .
|
"ON $UT.id = subscription.subscriber " .
|
||||||
'WHERE subscription.subscribed = ' . $notice->profile_id . ' ' .
|
'WHERE subscription.subscribed = ' . $notice->profile_id . ' ' .
|
||||||
|
'AND subscription.subscribed != subscription.subscriber ' .
|
||||||
"AND $UT.smsemail IS NOT null " .
|
"AND $UT.smsemail IS NOT null " .
|
||||||
"AND $UT.smsnotify = 1 " .
|
"AND $UT.smsnotify = 1 " .
|
||||||
'AND subscription.sms = 1 ');
|
'AND subscription.sms = 1 ');
|
||||||
|
@ -90,6 +90,7 @@ class NoticeForm extends Form
|
|||||||
$this->user = common_current_user();
|
$this->user = common_current_user();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->enctype = 'multipart/form-data';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -142,17 +143,21 @@ class NoticeForm extends Form
|
|||||||
'rows' => 4,
|
'rows' => 4,
|
||||||
'name' => 'status_textarea'),
|
'name' => 'status_textarea'),
|
||||||
($this->content) ? $this->content : '');
|
($this->content) ? $this->content : '');
|
||||||
|
|
||||||
$this->out->elementStart('dl', 'form_note');
|
$this->out->elementStart('dl', 'form_note');
|
||||||
$this->out->element('dt', null, _('Available characters'));
|
$this->out->element('dt', null, _('Available characters'));
|
||||||
$this->out->element('dd', array('id' => 'notice_text-count'),
|
$this->out->element('dd', array('id' => 'notice_text-count'),
|
||||||
'140');
|
'140');
|
||||||
$this->out->elementEnd('dl');
|
$this->out->elementEnd('dl');
|
||||||
|
$this->out->element('label', array('for' => 'notice_data-attach'), _('Attach'));
|
||||||
|
$this->out->element('input', array('id' => 'notice_data-attach',
|
||||||
|
'type' => 'file',
|
||||||
|
'name' => 'attach',
|
||||||
|
'title' => _('Attach a file')));
|
||||||
if ($this->action) {
|
if ($this->action) {
|
||||||
$this->out->hidden('notice_return-to', $this->action, 'returnto');
|
$this->out->hidden('notice_return-to', $this->action, 'returnto');
|
||||||
}
|
}
|
||||||
$this->out->hidden('notice_in-reply-to', $this->action, 'inreplyto');
|
$this->out->hidden('notice_in-reply-to', $this->action, 'inreplyto');
|
||||||
|
$this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,7 +85,7 @@ class NoticeList extends Widget
|
|||||||
{
|
{
|
||||||
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
||||||
$this->out->element('h2', null, _('Notices'));
|
$this->out->element('h2', null, _('Notices'));
|
||||||
$this->out->elementStart('ul', array('class' => 'notices'));
|
$this->out->elementStart('ol', array('class' => 'notices xoxo'));
|
||||||
|
|
||||||
$cnt = 0;
|
$cnt = 0;
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ class NoticeList extends Widget
|
|||||||
$item->show();
|
$item->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ol');
|
||||||
$this->out->elementEnd('div');
|
$this->out->elementEnd('div');
|
||||||
|
|
||||||
return $cnt;
|
return $cnt;
|
||||||
@ -205,6 +205,7 @@ class NoticeListItem extends Widget
|
|||||||
return 'shownotice' !== $this->out->args['action'];
|
return 'shownotice' !== $this->out->args['action'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
function attachmentCount($discriminant = true) {
|
function attachmentCount($discriminant = true) {
|
||||||
$file_oembed = new File_oembed;
|
$file_oembed = new File_oembed;
|
||||||
$query = "select count(*) as c from file_oembed join file_to_post on file_oembed.file_id = file_to_post.file_id where post_id=" . $this->notice->id;
|
$query = "select count(*) as c from file_oembed join file_to_post on file_oembed.file_id = file_to_post.file_id where post_id=" . $this->notice->id;
|
||||||
@ -212,11 +213,16 @@ class NoticeListItem extends Widget
|
|||||||
$file_oembed->fetch();
|
$file_oembed->fetch();
|
||||||
return intval($file_oembed->c);
|
return intval($file_oembed->c);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showWithAttachment() {
|
||||||
|
}
|
||||||
|
|
||||||
function showNoticeInfo()
|
function showNoticeInfo()
|
||||||
{
|
{
|
||||||
$this->out->elementStart('div', 'entry-content');
|
$this->out->elementStart('div', 'entry-content');
|
||||||
$this->showNoticeLink();
|
$this->showNoticeLink();
|
||||||
|
// $this->showWithAttachment();
|
||||||
$this->showNoticeSource();
|
$this->showNoticeSource();
|
||||||
$this->showContext();
|
$this->showContext();
|
||||||
$this->out->elementEnd('div');
|
$this->out->elementEnd('div');
|
||||||
@ -357,6 +363,10 @@ class NoticeListItem extends Widget
|
|||||||
// versions (>> 0.4.x)
|
// versions (>> 0.4.x)
|
||||||
$this->out->raw(common_render_content($this->notice->content, $this->notice));
|
$this->out->raw(common_render_content($this->notice->content, $this->notice));
|
||||||
}
|
}
|
||||||
|
$uploaded = $this->notice->getUploadedAttachment();
|
||||||
|
if ($uploaded) {
|
||||||
|
$this->out->element('a', array('href' => $uploaded, 'class' => 'attachment'), $uploaded);
|
||||||
|
}
|
||||||
$this->out->elementEnd('p');
|
$this->out->elementEnd('p');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,6 +397,7 @@ class NoticeListItem extends Widget
|
|||||||
$this->out->element('abbr', array('class' => 'published',
|
$this->out->element('abbr', array('class' => 'published',
|
||||||
'title' => $dt),
|
'title' => $dt),
|
||||||
common_date_string($this->notice->created));
|
common_date_string($this->notice->created));
|
||||||
|
|
||||||
$this->out->elementEnd('a');
|
$this->out->elementEnd('a');
|
||||||
$this->out->elementEnd('dd');
|
$this->out->elementEnd('dd');
|
||||||
$this->out->elementEnd('dl');
|
$this->out->elementEnd('dl');
|
||||||
|
@ -52,12 +52,12 @@ class NoticeSection extends Section
|
|||||||
{
|
{
|
||||||
$notices = $this->getNotices();
|
$notices = $this->getNotices();
|
||||||
$cnt = 0;
|
$cnt = 0;
|
||||||
$this->out->elementStart('ul', 'notices');
|
$this->out->elementStart('ol', 'notices xoxo');
|
||||||
while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) {
|
while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) {
|
||||||
$this->showNotice($notices);
|
$this->showNotice($notices);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ol');
|
||||||
return ($cnt > NOTICES_PER_SECTION);
|
return ($cnt > NOTICES_PER_SECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
lib/omb.php
10
lib/omb.php
@ -159,13 +159,9 @@ function omb_post_notice($notice, $remote_profile, $subscription)
|
|||||||
|
|
||||||
function omb_post_notice_keys($notice, $postnoticeurl, $tk, $secret)
|
function omb_post_notice_keys($notice, $postnoticeurl, $tk, $secret)
|
||||||
{
|
{
|
||||||
|
|
||||||
common_debug('Posting notice ' . $notice->id . ' to ' . $postnoticeurl, __FILE__);
|
|
||||||
|
|
||||||
$user = User::staticGet('id', $notice->profile_id);
|
$user = User::staticGet('id', $notice->profile_id);
|
||||||
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
common_debug('Failed to get user for notice ' . $notice->id . ', profile = ' . $notice->profile_id, __FILE__);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,8 +204,6 @@ function omb_post_notice_keys($notice, $postnoticeurl, $tk, $secret)
|
|||||||
$req->to_postdata(),
|
$req->to_postdata(),
|
||||||
array('User-Agent: Laconica/' . LACONICA_VERSION));
|
array('User-Agent: Laconica/' . LACONICA_VERSION));
|
||||||
|
|
||||||
common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__);
|
|
||||||
|
|
||||||
if ($result->status == 403) { # not authorized, don't send again
|
if ($result->status == 403) { # not authorized, don't send again
|
||||||
common_debug('403 result, deleting subscription', __FILE__);
|
common_debug('403 result, deleting subscription', __FILE__);
|
||||||
# FIXME: figure out how to delete this
|
# FIXME: figure out how to delete this
|
||||||
@ -286,14 +280,10 @@ function omb_update_profile($profile, $remote_profile, $subscription)
|
|||||||
|
|
||||||
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
|
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
|
||||||
|
|
||||||
common_debug('request URL = '.$req->get_normalized_http_url(), __FILE__);
|
|
||||||
common_debug('postdata = '.$req->to_postdata(), __FILE__);
|
|
||||||
$result = $fetcher->post($req->get_normalized_http_url(),
|
$result = $fetcher->post($req->get_normalized_http_url(),
|
||||||
$req->to_postdata(),
|
$req->to_postdata(),
|
||||||
array('User-Agent: Laconica/' . LACONICA_VERSION));
|
array('User-Agent: Laconica/' . LACONICA_VERSION));
|
||||||
|
|
||||||
common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__);
|
|
||||||
|
|
||||||
if (empty($result) || !$result) {
|
if (empty($result) || !$result) {
|
||||||
common_debug("Unable to contact " . $req->get_normalized_http_url());
|
common_debug("Unable to contact " . $req->get_normalized_http_url());
|
||||||
} else if ($result->status == 403) { # not authorized, don't send again
|
} else if ($result->status == 403) { # not authorized, don't send again
|
||||||
|
@ -164,6 +164,10 @@ class Router
|
|||||||
array('action' => 'newnotice'),
|
array('action' => 'newnotice'),
|
||||||
array('replyto' => '[A-Za-z0-9_-]+'));
|
array('replyto' => '[A-Za-z0-9_-]+'));
|
||||||
|
|
||||||
|
$m->connect('notice/:notice/file',
|
||||||
|
array('action' => 'file'),
|
||||||
|
array('notice' => '[0-9]+'));
|
||||||
|
|
||||||
$m->connect('notice/:notice',
|
$m->connect('notice/:notice',
|
||||||
array('action' => 'shownotice'),
|
array('action' => 'shownotice'),
|
||||||
array('notice' => '[0-9]+'));
|
array('notice' => '[0-9]+'));
|
||||||
|
@ -73,21 +73,82 @@ class TwitterapiAction extends Action
|
|||||||
|
|
||||||
function twitter_user_array($profile, $get_notice=false)
|
function twitter_user_array($profile, $get_notice=false)
|
||||||
{
|
{
|
||||||
|
|
||||||
$twitter_user = array();
|
$twitter_user = array();
|
||||||
|
|
||||||
$twitter_user['name'] = $profile->getBestName();
|
|
||||||
$twitter_user['followers_count'] = $this->count_subscriptions($profile);
|
|
||||||
$twitter_user['screen_name'] = $profile->nickname;
|
|
||||||
$twitter_user['description'] = ($profile->bio) ? $profile->bio : null;
|
|
||||||
$twitter_user['location'] = ($profile->location) ? $profile->location : null;
|
|
||||||
$twitter_user['id'] = intval($profile->id);
|
$twitter_user['id'] = intval($profile->id);
|
||||||
|
$twitter_user['name'] = $profile->getBestName();
|
||||||
|
$twitter_user['screen_name'] = $profile->nickname;
|
||||||
|
$twitter_user['location'] = ($profile->location) ? $profile->location : null;
|
||||||
|
$twitter_user['description'] = ($profile->bio) ? $profile->bio : null;
|
||||||
|
|
||||||
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
|
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
|
||||||
|
$twitter_user['profile_image_url'] = ($avatar) ? $avatar->displayUrl() :
|
||||||
|
Avatar::defaultImage(AVATAR_STREAM_SIZE);
|
||||||
|
|
||||||
$twitter_user['profile_image_url'] = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_STREAM_SIZE);
|
|
||||||
$twitter_user['protected'] = false; # not supported by Laconica yet
|
|
||||||
$twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null;
|
$twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null;
|
||||||
|
$twitter_user['protected'] = false; # not supported by Laconica yet
|
||||||
|
$twitter_user['followers_count'] = $this->count_subscriptions($profile);
|
||||||
|
|
||||||
|
// To be supported soon...
|
||||||
|
$twitter_user['profile_background_color'] = '';
|
||||||
|
$twitter_user['profile_text_color'] = '';
|
||||||
|
$twitter_user['profile_link_color'] = '';
|
||||||
|
$twitter_user['profile_sidebar_fill_color'] = '';
|
||||||
|
$twitter_user['profile_sidebar_border_color'] = '';
|
||||||
|
|
||||||
|
$subbed = DB_DataObject::factory('subscription');
|
||||||
|
$subbed->subscriber = $profile->id;
|
||||||
|
$subbed_count = (int) $subbed->count() - 1;
|
||||||
|
$twitter_user['friends_count'] = (is_int($subbed_count)) ? $subbed_count : 0;
|
||||||
|
|
||||||
|
$twitter_user['created_at'] = $this->date_twitter($profile->created);
|
||||||
|
|
||||||
|
$faves = DB_DataObject::factory('fave');
|
||||||
|
$faves->user_id = $user->id;
|
||||||
|
$faves_count = (int) $faves->count();
|
||||||
|
$twitter_user['favourites_count'] = $faves_count; // British spelling!
|
||||||
|
|
||||||
|
// Need to pull up the user for some of this
|
||||||
|
$user = User::staticGet($profile->id);
|
||||||
|
|
||||||
|
$timezone = 'UTC';
|
||||||
|
|
||||||
|
if ($user->timezone) {
|
||||||
|
$timezone = $user->timezone;
|
||||||
|
}
|
||||||
|
|
||||||
|
$t = new DateTime;
|
||||||
|
$t->setTimezone(new DateTimeZone($timezone));
|
||||||
|
|
||||||
|
$twitter_user['utc_offset'] = $t->format('Z');
|
||||||
|
$twitter_user['time_zone'] = $timezone;
|
||||||
|
|
||||||
|
// To be supported some day, perhaps
|
||||||
|
$twitter_user['profile_background_image_url'] = '';
|
||||||
|
$twitter_user['profile_background_tile'] = false;
|
||||||
|
|
||||||
|
$notices = DB_DataObject::factory('notice');
|
||||||
|
$notices->profile_id = $profile->id;
|
||||||
|
$notice_count = (int) $notices->count();
|
||||||
|
|
||||||
|
$twitter_user['statuses_count'] = (is_int($notice_count)) ? $notice_count : 0;
|
||||||
|
|
||||||
|
// Is the requesting user following this user?
|
||||||
|
$twitter_user['following'] = false;
|
||||||
|
$twitter_user['notifications'] = false;
|
||||||
|
|
||||||
|
if (isset($apidata['user'])) {
|
||||||
|
|
||||||
|
$twitter_user['following'] = $apidata['user']->isSubscribed($profile);
|
||||||
|
|
||||||
|
// Notifications on?
|
||||||
|
$sub = Subscription::pkeyGet(array('subscriber' =>
|
||||||
|
$apidata['user']->id, 'subscribed' => $profile->id));
|
||||||
|
|
||||||
|
if ($sub) {
|
||||||
|
$twitter_user['notifications'] = ($sub->jabber || $sub->sms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($get_notice) {
|
if ($get_notice) {
|
||||||
$notice = $profile->getCurrentNotice();
|
$notice = $profile->getCurrentNotice();
|
||||||
@ -612,7 +673,27 @@ class TwitterapiAction extends Action
|
|||||||
function get_user($id, $apidata=null)
|
function get_user($id, $apidata=null)
|
||||||
{
|
{
|
||||||
if (!$id) {
|
if (!$id) {
|
||||||
return $apidata['user'];
|
|
||||||
|
// Twitter supports these other ways of passing the user ID
|
||||||
|
if (is_numeric($this->arg('id'))) {
|
||||||
|
return User::staticGet($this->arg('id'));
|
||||||
|
} else if ($this->arg('id')) {
|
||||||
|
$nickname = common_canonical_nickname($this->arg('id'));
|
||||||
|
return User::staticGet('nickname', $nickname);
|
||||||
|
} else if ($this->arg('user_id')) {
|
||||||
|
// This is to ensure that a non-numeric user_id still
|
||||||
|
// overrides screen_name even if it doesn't get used
|
||||||
|
if (is_numeric($this->arg('user_id'))) {
|
||||||
|
return User::staticGet('id', $this->arg('user_id'));
|
||||||
|
}
|
||||||
|
} else if ($this->arg('screen_name')) {
|
||||||
|
$nickname = common_canonical_nickname($this->arg('screen_name'));
|
||||||
|
return User::staticGet('nickname', $nickname);
|
||||||
|
} else {
|
||||||
|
// Fall back to trying the currently authenticated user
|
||||||
|
return $apidata['user'];
|
||||||
|
}
|
||||||
|
|
||||||
} else if (is_numeric($id)) {
|
} else if (is_numeric($id)) {
|
||||||
return User::staticGet($id);
|
return User::staticGet($id);
|
||||||
} else {
|
} else {
|
||||||
|
33
lib/util.php
33
lib/util.php
@ -499,6 +499,11 @@ function common_linkify($url) {
|
|||||||
|
|
||||||
// if this URL is an attachment, then we set class='attachment' and id='attahcment-ID'
|
// if this URL is an attachment, then we set class='attachment' and id='attahcment-ID'
|
||||||
// where ID is the id of the attachment for the given URL.
|
// where ID is the id of the attachment for the given URL.
|
||||||
|
//
|
||||||
|
// we need a better test telling what can be shown as an attachment
|
||||||
|
// we're currently picking up oembeds only.
|
||||||
|
// I think the best option is another file_view table in the db
|
||||||
|
// and associated dbobject.
|
||||||
$query = "select file_oembed.file_id as file_id from file join file_oembed on file.id = file_oembed.file_id where file.url='$longurl'";
|
$query = "select file_oembed.file_id as file_id from file join file_oembed on file.id = file_oembed.file_id where file.url='$longurl'";
|
||||||
$file = new File;
|
$file = new File;
|
||||||
$file->query($query);
|
$file->query($query);
|
||||||
@ -895,6 +900,34 @@ function common_enqueue_notice($notice)
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function common_post_inbox_transports()
|
||||||
|
{
|
||||||
|
$transports = array('omb', 'sms');
|
||||||
|
|
||||||
|
if (common_config('xmpp', 'enabled')) {
|
||||||
|
$transports = array_merge($transports, array('jabber', 'public'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transports;
|
||||||
|
}
|
||||||
|
|
||||||
|
function common_enqueue_notice_transport($notice, $transport)
|
||||||
|
{
|
||||||
|
$qi = new Queue_item();
|
||||||
|
$qi->notice_id = $notice->id;
|
||||||
|
$qi->transport = $transport;
|
||||||
|
$qi->created = $notice->created;
|
||||||
|
$result = $qi->insert();
|
||||||
|
if (!$result) {
|
||||||
|
$last_error = &PEAR::getStaticProperty('DB_DataObject','lastError');
|
||||||
|
common_log(LOG_ERR, 'DB error inserting queue item: ' . $last_error->message);
|
||||||
|
throw new ServerException('DB error inserting queue item: ' . $last_error->message);
|
||||||
|
>>>>>>> 0.7.x:lib/util.php
|
||||||
|
}
|
||||||
|
common_log(LOG_DEBUG, 'complete queueing notice ID = ' . $notice->id . ' for ' . $transport);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function common_real_broadcast($notice, $remote=false)
|
function common_real_broadcast($notice, $remote=false)
|
||||||
{
|
{
|
||||||
$success = true;
|
$success = true;
|
||||||
|
73
plugins/FBConnect/FBC_XDReceiver.php
Normal file
73
plugins/FBConnect/FBC_XDReceiver.php
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates the cross domain communication channel file
|
||||||
|
* (xd_receiver.html). By generating it we can add some caching
|
||||||
|
* instructions.
|
||||||
|
*
|
||||||
|
* See: http://wiki.developers.facebook.com/index.php/Cross_Domain_Communication_Channel
|
||||||
|
*/
|
||||||
|
class FBC_XDReceiverAction extends Action
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do we need to write to the database?
|
||||||
|
*
|
||||||
|
* @return boolean true
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isReadonly()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a request
|
||||||
|
*
|
||||||
|
* @param array $args Arguments from $_REQUEST
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
// Parent handling, including cache check
|
||||||
|
parent::handle($args);
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPage()
|
||||||
|
{
|
||||||
|
// cache the xd_receiver
|
||||||
|
header('Cache-Control: max-age=225065900');
|
||||||
|
header('Expires:');
|
||||||
|
header('Pragma:');
|
||||||
|
|
||||||
|
$this->startXML('html',
|
||||||
|
'-//W3C//DTD XHTML 1.0 Strict//EN',
|
||||||
|
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
|
||||||
|
|
||||||
|
$language = $this->getLanguage();
|
||||||
|
|
||||||
|
$this->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
|
||||||
|
'xml:lang' => $language,
|
||||||
|
'lang' => $language));
|
||||||
|
$this->elementStart('head');
|
||||||
|
$this->element('title', null, 'cross domain receiver page');
|
||||||
|
$this->element('script',
|
||||||
|
array('src' =>
|
||||||
|
'http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.debug.js',
|
||||||
|
'type' => 'text/javascript'), '');
|
||||||
|
$this->elementEnd('head');
|
||||||
|
$this->elementStart('body');
|
||||||
|
$this->elementEnd('body');
|
||||||
|
|
||||||
|
$this->elementEnd('html');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -62,7 +62,28 @@ class FBConnectauthAction extends Action
|
|||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
|
|
||||||
if (common_is_real_login()) {
|
if (common_is_real_login()) {
|
||||||
$this->clientError(_('Already logged in.'));
|
|
||||||
|
// User is already logged in. Does she already have a linked Facebook acct?
|
||||||
|
$flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_CONNECT_SERVICE);
|
||||||
|
|
||||||
|
if ($flink) {
|
||||||
|
|
||||||
|
// User already has a linked Facebook account and shouldn't be here
|
||||||
|
common_debug('There is already a local user (' . $flink->user_id .
|
||||||
|
') linked with this Facebook (' . $this->fbuid . ').');
|
||||||
|
|
||||||
|
// We don't want these cookies
|
||||||
|
getFacebook()->clear_cookie_state();
|
||||||
|
|
||||||
|
$this->clientError(_('There is already a local user linked with this Facebook.'));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// User came from the Facebook connect settings tab, and
|
||||||
|
// probably just wants to link/relink their Facebook account
|
||||||
|
$this->connectUser();
|
||||||
|
}
|
||||||
|
|
||||||
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
|
||||||
$token = $this->trimmed('token');
|
$token = $this->trimmed('token');
|
||||||
@ -78,7 +99,7 @@ class FBConnectauthAction extends Action
|
|||||||
}
|
}
|
||||||
$this->createNewUser();
|
$this->createNewUser();
|
||||||
} else if ($this->arg('connect')) {
|
} else if ($this->arg('connect')) {
|
||||||
$this->connectUser();
|
$this->connectNewUser();
|
||||||
} else {
|
} else {
|
||||||
common_debug(print_r($this->args, true), __FILE__);
|
common_debug(print_r($this->args, true), __FILE__);
|
||||||
$this->showForm(_('Something weird happened.'),
|
$this->showForm(_('Something weird happened.'),
|
||||||
@ -259,7 +280,7 @@ class FBConnectauthAction extends Action
|
|||||||
303);
|
303);
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectUser()
|
function connectNewUser()
|
||||||
{
|
{
|
||||||
$nickname = $this->trimmed('nickname');
|
$nickname = $this->trimmed('nickname');
|
||||||
$password = $this->trimmed('password');
|
$password = $this->trimmed('password');
|
||||||
@ -290,6 +311,23 @@ class FBConnectauthAction extends Action
|
|||||||
$this->goHome($user->nickname);
|
$this->goHome($user->nickname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function connectUser()
|
||||||
|
{
|
||||||
|
$user = common_current_user();
|
||||||
|
|
||||||
|
$result = $this->flinkUser($user->id, $this->fbuid);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
$this->serverError(_('Error connecting user to Facebook.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
common_debug("Connected Facebook user $this->fbuid to local user $user->id");
|
||||||
|
|
||||||
|
// Return to Facebook connection settings tab
|
||||||
|
common_redirect(common_local_url('FBConnectSettings'), 303);
|
||||||
|
}
|
||||||
|
|
||||||
function tryLogin()
|
function tryLogin()
|
||||||
{
|
{
|
||||||
common_debug("Trying Facebook Login...");
|
common_debug("Trying Facebook Login...");
|
||||||
|
@ -58,8 +58,6 @@ class FBConnectLoginAction extends Action
|
|||||||
function showContent() {
|
function showContent() {
|
||||||
|
|
||||||
$this->elementStart('fieldset');
|
$this->elementStart('fieldset');
|
||||||
|
|
||||||
|
|
||||||
$this->element('fb:login-button', array('onlogin' => 'goto_login()',
|
$this->element('fb:login-button', array('onlogin' => 'goto_login()',
|
||||||
'length' => 'long'));
|
'length' => 'long'));
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ require_once INSTALLDIR . '/plugins/FBConnect/FBConnectLogin.php';
|
|||||||
require_once INSTALLDIR . '/plugins/FBConnect/FBConnectSettings.php';
|
require_once INSTALLDIR . '/plugins/FBConnect/FBConnectSettings.php';
|
||||||
require_once INSTALLDIR . '/plugins/FBConnect/FBCLoginGroupNav.php';
|
require_once INSTALLDIR . '/plugins/FBConnect/FBCLoginGroupNav.php';
|
||||||
require_once INSTALLDIR . '/plugins/FBConnect/FBCSettingsNav.php';
|
require_once INSTALLDIR . '/plugins/FBConnect/FBCSettingsNav.php';
|
||||||
|
require_once INSTALLDIR . '/plugins/FBConnect/FBC_XDReceiver.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin to enable Facebook Connect
|
* Plugin to enable Facebook Connect
|
||||||
@ -62,27 +63,19 @@ class FBConnectPlugin extends Plugin
|
|||||||
$m->connect('main/facebookconnect', array('action' => 'FBConnectAuth'));
|
$m->connect('main/facebookconnect', array('action' => 'FBConnectAuth'));
|
||||||
$m->connect('main/facebooklogin', array('action' => 'FBConnectLogin'));
|
$m->connect('main/facebooklogin', array('action' => 'FBConnectLogin'));
|
||||||
$m->connect('settings/facebook', array('action' => 'FBConnectSettings'));
|
$m->connect('settings/facebook', array('action' => 'FBConnectSettings'));
|
||||||
|
$m->connect('xd_receiver.html', array('action' => 'FBC_XDReceiver'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add in xmlns:fb
|
// Add in xmlns:fb
|
||||||
function onStartShowHTML($action)
|
function onStartShowHTML($action)
|
||||||
{
|
{
|
||||||
$httpaccept = isset($_SERVER['HTTP_ACCEPT']) ?
|
// XXX: Horrible hack to make Safari, FF2, and Chrome work with
|
||||||
$_SERVER['HTTP_ACCEPT'] : null;
|
// Facebook Connect. These browser cannot use Facebook's
|
||||||
|
// DOM parsing routines unless the mime type of the page is
|
||||||
// XXX: allow content negotiation for RDF, RSS, or XRDS
|
// text/html even though Facebook Connect uses XHTML. This is
|
||||||
|
// A bug in Facebook Connect, and this is a temporary solution
|
||||||
$cp = common_accept_to_prefs($httpaccept);
|
// until they fix their JavaScript libs.
|
||||||
$sp = common_accept_to_prefs(PAGE_TYPE_PREFS);
|
header('Content-Type: text/html');
|
||||||
|
|
||||||
$type = common_negotiate_type($cp, $sp);
|
|
||||||
|
|
||||||
if (!$type) {
|
|
||||||
throw new ClientException(_('This page is not available in a '.
|
|
||||||
'media type you accept'), 406);
|
|
||||||
}
|
|
||||||
|
|
||||||
header('Content-Type: '.$type);
|
|
||||||
|
|
||||||
$action->extraHeaders();
|
$action->extraHeaders();
|
||||||
|
|
||||||
@ -101,20 +94,27 @@ class FBConnectPlugin extends Plugin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEndShowLaconicaScripts($action)
|
// Note: this script needs to appear in the <body>
|
||||||
{
|
|
||||||
$action->element('script',
|
|
||||||
array('type' => 'text/javascript',
|
|
||||||
'src' => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php'),
|
|
||||||
' ');
|
|
||||||
|
|
||||||
|
function onStartShowHeader($action)
|
||||||
|
{
|
||||||
$apikey = common_config('facebook', 'apikey');
|
$apikey = common_config('facebook', 'apikey');
|
||||||
$plugin_path = common_path('plugins/FBConnect');
|
$plugin_path = common_path('plugins/FBConnect');
|
||||||
|
|
||||||
$login_url = common_local_url('FBConnectAuth');
|
$login_url = common_local_url('FBConnectAuth');
|
||||||
$logout_url = common_local_url('logout');
|
$logout_url = common_local_url('logout');
|
||||||
|
|
||||||
$html = sprintf('<script type="text/javascript">FB.init("%s", "%s/xd_receiver.htm");
|
// XXX: Facebook says we don't need this FB_RequireFeatures(),
|
||||||
|
// but we actually do, for IE and Safari. Gar.
|
||||||
|
|
||||||
|
$html = sprintf('<script type="text/javascript">
|
||||||
|
window.onload = function () {
|
||||||
|
FB_RequireFeatures(
|
||||||
|
["XFBML"],
|
||||||
|
function() {
|
||||||
|
FB.Facebook.init("%s", "../xd_receiver.html");
|
||||||
|
}
|
||||||
|
); }
|
||||||
|
|
||||||
function goto_login() {
|
function goto_login() {
|
||||||
window.location = "%s";
|
window.location = "%s";
|
||||||
@ -123,13 +123,23 @@ class FBConnectPlugin extends Plugin
|
|||||||
function goto_logout() {
|
function goto_logout() {
|
||||||
window.location = "%s";
|
window.location = "%s";
|
||||||
}
|
}
|
||||||
|
</script>', $apikey,
|
||||||
</script>', $apikey, $plugin_path, $login_url, $logout_url);
|
$login_url, $logout_url);
|
||||||
|
|
||||||
|
|
||||||
$action->raw($html);
|
$action->raw($html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: this script needs to appear as close as possible to </body>
|
||||||
|
|
||||||
|
function onEndShowFooter($action)
|
||||||
|
{
|
||||||
|
|
||||||
|
$action->element('script',
|
||||||
|
array('type' => 'text/javascript',
|
||||||
|
'src' => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php'),
|
||||||
|
'');
|
||||||
|
}
|
||||||
|
|
||||||
function onEndShowLaconicaStyles($action)
|
function onEndShowLaconicaStyles($action)
|
||||||
{
|
{
|
||||||
$action->element('link', array('rel' => 'stylesheet',
|
$action->element('link', array('rel' => 'stylesheet',
|
||||||
@ -143,24 +153,8 @@ class FBConnectPlugin extends Plugin
|
|||||||
|
|
||||||
if ($user) {
|
if ($user) {
|
||||||
|
|
||||||
$action->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
|
$flink = Foreign_link::getByUserId($user->id,
|
||||||
_('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
|
FACEBOOK_CONNECT_SERVICE);
|
||||||
$action->menuItem(common_local_url('profilesettings'),
|
|
||||||
_('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
|
|
||||||
if (common_config('xmpp', 'enabled')) {
|
|
||||||
$action->menuItem(common_local_url('imsettings'),
|
|
||||||
_('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
|
|
||||||
} else {
|
|
||||||
$action->menuItem(common_local_url('smssettings'),
|
|
||||||
_('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
|
|
||||||
}
|
|
||||||
$action->menuItem(common_local_url('invite'),
|
|
||||||
_('Invite'),
|
|
||||||
sprintf(_('Invite friends and colleagues to join you on %s'),
|
|
||||||
common_config('site', 'name')),
|
|
||||||
false, 'nav_invitecontact');
|
|
||||||
|
|
||||||
$flink = Foreign_link::getByUserId($user->id, FACEBOOK_CONNECT_SERVICE);
|
|
||||||
$fbuid = 0;
|
$fbuid = 0;
|
||||||
|
|
||||||
if ($flink) {
|
if ($flink) {
|
||||||
@ -195,9 +189,25 @@ class FBConnectPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to override the Logout link to make it do FB stuff
|
$action->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
|
||||||
|
_('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
|
||||||
|
$action->menuItem(common_local_url('profilesettings'),
|
||||||
|
_('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
|
||||||
|
if (common_config('xmpp', 'enabled')) {
|
||||||
|
$action->menuItem(common_local_url('imsettings'),
|
||||||
|
_('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
|
||||||
|
} else {
|
||||||
|
$action->menuItem(common_local_url('smssettings'),
|
||||||
|
_('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
|
||||||
|
}
|
||||||
|
$action->menuItem(common_local_url('invite'),
|
||||||
|
_('Invite'),
|
||||||
|
sprintf(_('Invite friends and colleagues to join you on %s'),
|
||||||
|
common_config('site', 'name')),
|
||||||
|
false, 'nav_invitecontact');
|
||||||
|
|
||||||
if ($fbuid > 0) {
|
// Need to override the Logout link to make it do FB stuff
|
||||||
|
if ($flink && $fbuid > 0) {
|
||||||
|
|
||||||
$logout_url = common_local_url('logout');
|
$logout_url = common_local_url('logout');
|
||||||
$title = _('Logout from the site');
|
$title = _('Logout from the site');
|
||||||
@ -258,21 +268,32 @@ class FBConnectPlugin extends Plugin
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEndLogout($action)
|
function onStartLogout($action)
|
||||||
{
|
{
|
||||||
try {
|
$user = common_current_user();
|
||||||
|
|
||||||
|
$flink = Foreign_link::getByUserId($user->id, FACEBOOK_CONNECT_SERVICE);
|
||||||
|
|
||||||
|
$action->logout();
|
||||||
|
|
||||||
|
if ($flink) {
|
||||||
|
|
||||||
$facebook = getFacebook();
|
$facebook = getFacebook();
|
||||||
$fbuid = $facebook->get_loggedin_user();
|
|
||||||
|
|
||||||
if ($fbuid > 0) {
|
try {
|
||||||
$facebook->logout(common_local_url('public'));
|
$fbuid = $facebook->get_loggedin_user();
|
||||||
|
|
||||||
|
if ($fbuid > 0) {
|
||||||
|
$facebook->logout(common_local_url('public'));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
common_log(LOG_WARNING, 'Could\'t logout of Facebook: ' .
|
||||||
|
$e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception $e) {
|
|
||||||
common_log(LOG_WARNING, 'Could\'t logout of Facebook: ' .
|
|
||||||
$e->getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -78,63 +78,73 @@ class FBConnectSettingsAction extends ConnectSettingsAction
|
|||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
$flink = Foreign_link::getByUserID($user->id, FACEBOOK_CONNECT_SERVICE);
|
$flink = Foreign_link::getByUserID($user->id, FACEBOOK_CONNECT_SERVICE);
|
||||||
|
|
||||||
if (!$flink) {
|
|
||||||
|
|
||||||
$this->element('p', 'form_note',
|
|
||||||
_('There is no Facebook user connected to this account.'));
|
|
||||||
|
|
||||||
$this->element('fb:login-button', array('onlogin' => 'goto_login()',
|
|
||||||
'length' => 'long'));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->element('p', 'form_note',
|
|
||||||
_('Connected Facebook user:'));
|
|
||||||
|
|
||||||
$this->elementStart('p', array('class' => 'facebook-user-display'));
|
|
||||||
$this->elementStart('fb:profile-pic',
|
|
||||||
array('uid' => $flink->foreign_id,
|
|
||||||
'size' => 'square',
|
|
||||||
'linked' => 'true',
|
|
||||||
'facebook-logo' => 'true'));
|
|
||||||
$this->elementEnd('fb:profile-pic');
|
|
||||||
|
|
||||||
$this->elementStart('fb:name', array('uid' => $flink->foreign_id));
|
|
||||||
$this->elementEnd('fb:name');
|
|
||||||
$this->elementEnd('p');
|
|
||||||
|
|
||||||
$this->elementStart('form', array('method' => 'post',
|
$this->elementStart('form', array('method' => 'post',
|
||||||
'id' => 'form_settings_facebook',
|
'id' => 'form_settings_facebook',
|
||||||
'class' => 'form_settings',
|
'class' => 'form_settings',
|
||||||
'action' =>
|
'action' =>
|
||||||
common_local_url('FBConnectSettings')));
|
common_local_url('FBConnectSettings')));
|
||||||
|
|
||||||
$this->hidden('token', common_session_token());
|
if (!$flink) {
|
||||||
|
|
||||||
$this->elementStart('fieldset');
|
$this->element('p', 'instructions',
|
||||||
|
_('There is no Facebook user connected to this account.'));
|
||||||
|
|
||||||
$this->element('legend', null, _('Disconnect my account from Facebook'));
|
$this->element('fb:login-button', array('onlogin' => 'goto_login()',
|
||||||
|
'length' => 'long'));
|
||||||
|
|
||||||
if (!$user->password) {
|
|
||||||
|
|
||||||
$this->elementStart('p', array('class' => 'form_guide'));
|
|
||||||
$this->text(_('Disconnecting your Faceboook ' .
|
|
||||||
'would make it impossible to log in! Please '));
|
|
||||||
$this->element('a',
|
|
||||||
array('href' => common_local_url('passwordsettings')),
|
|
||||||
_('set a password'));
|
|
||||||
|
|
||||||
$this->text(_(' first.'));
|
|
||||||
$this->elementEnd('p');
|
|
||||||
} else {
|
} else {
|
||||||
$this->submit('disconnect', _('Disconnect'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->elementEnd('fieldset');
|
$this->element('p', 'form_note',
|
||||||
|
_('Connected Facebook user'));
|
||||||
|
|
||||||
|
$this->elementStart('p', array('class' => 'facebook-user-display'));
|
||||||
|
$this->elementStart('fb:profile-pic',
|
||||||
|
array('uid' => $flink->foreign_id,
|
||||||
|
'size' => 'small',
|
||||||
|
'linked' => 'true',
|
||||||
|
'facebook-logo' => 'true'));
|
||||||
|
$this->elementEnd('fb:profile-pic');
|
||||||
|
|
||||||
|
$this->elementStart('fb:name', array('uid' => $flink->foreign_id,
|
||||||
|
'useyou' => 'false'));
|
||||||
|
$this->elementEnd('fb:name');
|
||||||
|
$this->elementEnd('p');
|
||||||
|
|
||||||
|
$this->hidden('token', common_session_token());
|
||||||
|
|
||||||
|
$this->elementStart('fieldset');
|
||||||
|
|
||||||
|
$this->element('legend', null, _('Disconnect my account from Facebook'));
|
||||||
|
|
||||||
|
if (!$user->password) {
|
||||||
|
|
||||||
|
$this->elementStart('p', array('class' => 'form_guide'));
|
||||||
|
$this->text(_('Disconnecting your Faceboook ' .
|
||||||
|
'would make it impossible to log in! Please '));
|
||||||
|
$this->element('a',
|
||||||
|
array('href' => common_local_url('passwordsettings')),
|
||||||
|
_('set a password'));
|
||||||
|
|
||||||
|
$this->text(_(' first.'));
|
||||||
|
$this->elementEnd('p');
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$note = 'Keep your %s account but disconnect from Facebook. ' .
|
||||||
|
'You\'ll use your %s password to log in.';
|
||||||
|
|
||||||
|
$site = common_config('site', 'name');
|
||||||
|
|
||||||
|
$this->element('p', 'instructions',
|
||||||
|
sprintf($note, $site, $site));
|
||||||
|
|
||||||
|
$this->submit('disconnect', _('Disconnect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
}
|
||||||
|
|
||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,8 +181,7 @@ class FBConnectSettingsAction extends ConnectSettingsAction
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// XXX: not sure what exactly to do here
|
// Clear FB Connect cookies out
|
||||||
|
|
||||||
$facebook = getFacebook();
|
$facebook = getFacebook();
|
||||||
$facebook->clear_cookie_state();
|
$facebook->clear_cookie_state();
|
||||||
|
|
||||||
@ -182,7 +191,7 @@ class FBConnectSettingsAction extends ConnectSettingsAction
|
|||||||
$e->getMessage());
|
$e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->showForm(_('Facebook user disconnected.'), true);
|
$this->showForm(_('You have disconnected from Facebook.'), true);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$this->showForm(_('Not sure what you\'re trying to do.'));
|
$this->showForm(_('Not sure what you\'re trying to do.'));
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" >
|
|
||||||
<head>
|
|
||||||
<title>cross domain receiver page</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.debug.js" type="text/javascript"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
368
scripts/fixup_utf8.php
Normal file
368
scripts/fixup_utf8.php
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Laconica - a distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2009, Control Yourself, 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(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_set("max_execution_time", "0");
|
||||||
|
ini_set("max_input_time", "0");
|
||||||
|
set_time_limit(0);
|
||||||
|
mb_internal_encoding('UTF-8');
|
||||||
|
|
||||||
|
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||||
|
define('LACONICA', true);
|
||||||
|
|
||||||
|
require_once(INSTALLDIR . '/lib/common.php');
|
||||||
|
require_once('DB.php');
|
||||||
|
|
||||||
|
class UTF8FixerUpper
|
||||||
|
{
|
||||||
|
var $dbl = null;
|
||||||
|
var $dbu = null;
|
||||||
|
var $args = array();
|
||||||
|
|
||||||
|
function __construct($args)
|
||||||
|
{
|
||||||
|
$this->args = $args;
|
||||||
|
|
||||||
|
if (array_key_exists('max_date', $args)) {
|
||||||
|
$this->max_date = strftime('%Y-%m-%d %H:%M:%S', strtotime($args['max_date']));
|
||||||
|
} else {
|
||||||
|
$this->max_date = strftime('%Y-%m-%d %H:%M:%S', time());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->dbl = $this->doConnect('latin1');
|
||||||
|
|
||||||
|
if (empty($this->dbl)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->dbu = $this->doConnect('utf8');
|
||||||
|
|
||||||
|
if (empty($this->dbu)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doConnect($charset)
|
||||||
|
{
|
||||||
|
$db = DB::connect(common_config('db', 'database'),
|
||||||
|
array('persistent' => false));
|
||||||
|
|
||||||
|
if (PEAR::isError($db)) {
|
||||||
|
echo "ERROR: " . $db->getMessage() . "\n";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn = $db->connection;
|
||||||
|
|
||||||
|
$succ = mysqli_set_charset($conn, $charset);
|
||||||
|
|
||||||
|
if (!$succ) {
|
||||||
|
echo "ERROR: couldn't set charset\n";
|
||||||
|
$db->disconnect();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $db->autoCommit(true);
|
||||||
|
|
||||||
|
if (PEAR::isError($result)) {
|
||||||
|
echo "ERROR: " . $result->getMessage() . "\n";
|
||||||
|
$db->disconnect();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fixup()
|
||||||
|
{
|
||||||
|
$this->fixupNotices($this->args['max_notice'],
|
||||||
|
$this->args['min_notice']);
|
||||||
|
$this->fixupProfiles();
|
||||||
|
$this->fixupGroups();
|
||||||
|
$this->fixupMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
function fixupNotices($max_id, $min_id) {
|
||||||
|
|
||||||
|
// Do a separate DB connection
|
||||||
|
|
||||||
|
$sth = $this->dbu->prepare("UPDATE notice SET content = UNHEX(?), rendered = UNHEX(?) WHERE id = ?");
|
||||||
|
|
||||||
|
if (PEAR::isError($sth)) {
|
||||||
|
echo "ERROR: " . $sth->getMessage() . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'SELECT id, content, rendered FROM notice ' .
|
||||||
|
'WHERE LENGTH(content) != CHAR_LENGTH(content) '.
|
||||||
|
'AND modified < "'.$this->max_date.'" ';
|
||||||
|
|
||||||
|
if (!empty($max_id)) {
|
||||||
|
$sql .= ' AND id <= ' . $max_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($min_id)) {
|
||||||
|
$sql .= ' AND id >= ' . $min_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= ' ORDER BY id DESC';
|
||||||
|
|
||||||
|
$rn = $this->dbl->query($sql);
|
||||||
|
|
||||||
|
if (PEAR::isError($rn)) {
|
||||||
|
echo "ERROR: " . $rn->getMessage() . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Number of rows: " . $rn->numRows() . "\n";
|
||||||
|
|
||||||
|
$notice = array();
|
||||||
|
|
||||||
|
while (DB_OK == $rn->fetchInto($notice)) {
|
||||||
|
|
||||||
|
$id = ($notice[0])+0;
|
||||||
|
$content = bin2hex($notice[1]);
|
||||||
|
$rendered = bin2hex($notice[2]);
|
||||||
|
|
||||||
|
echo "$id...";
|
||||||
|
|
||||||
|
$result =& $this->dbu->execute($sth, array($content, $rendered, $id));
|
||||||
|
|
||||||
|
if (PEAR::isError($result)) {
|
||||||
|
echo "ERROR: " . $result->getMessage() . "\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cnt = $this->dbu->affectedRows();
|
||||||
|
|
||||||
|
if ($cnt != 1) {
|
||||||
|
echo "ERROR: 0 rows affected\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notice = Notice::staticGet('id', $id);
|
||||||
|
$notice->decache();
|
||||||
|
$notice->free();
|
||||||
|
|
||||||
|
echo "OK\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fixupProfiles()
|
||||||
|
{
|
||||||
|
// Do a separate DB connection
|
||||||
|
|
||||||
|
$sth = $this->dbu->prepare("UPDATE profile SET ".
|
||||||
|
"fullname = UNHEX(?),".
|
||||||
|
"location = UNHEX(?), ".
|
||||||
|
"bio = UNHEX(?) ".
|
||||||
|
"WHERE id = ?");
|
||||||
|
|
||||||
|
if (PEAR::isError($sth)) {
|
||||||
|
echo "ERROR: " . $sth->getMessage() . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'SELECT id, fullname, location, bio FROM profile ' .
|
||||||
|
'WHERE (LENGTH(fullname) != CHAR_LENGTH(fullname) '.
|
||||||
|
'OR LENGTH(location) != CHAR_LENGTH(location) '.
|
||||||
|
'OR LENGTH(bio) != CHAR_LENGTH(bio)) '.
|
||||||
|
'AND modified < "'.$this->max_date.'" '.
|
||||||
|
' ORDER BY modified DESC';
|
||||||
|
|
||||||
|
$rn = $this->dbl->query($sql);
|
||||||
|
|
||||||
|
if (PEAR::isError($rn)) {
|
||||||
|
echo "ERROR: " . $rn->getMessage() . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Number of rows: " . $rn->numRows() . "\n";
|
||||||
|
|
||||||
|
$profile = array();
|
||||||
|
|
||||||
|
while (DB_OK == $rn->fetchInto($profile)) {
|
||||||
|
|
||||||
|
$id = ($profile[0])+0;
|
||||||
|
$fullname = bin2hex($profile[1]);
|
||||||
|
$location = bin2hex($profile[2]);
|
||||||
|
$bio = bin2hex($profile[3]);
|
||||||
|
|
||||||
|
echo "$id...";
|
||||||
|
|
||||||
|
$result =& $this->dbu->execute($sth, array($fullname, $location, $bio, $id));
|
||||||
|
|
||||||
|
if (PEAR::isError($result)) {
|
||||||
|
echo "ERROR: " . $result->getMessage() . "\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cnt = $this->dbu->affectedRows();
|
||||||
|
|
||||||
|
if ($cnt != 1) {
|
||||||
|
echo "ERROR: 0 rows affected\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$profile = Profile::staticGet('id', $id);
|
||||||
|
$profile->decache();
|
||||||
|
$profile->free();
|
||||||
|
|
||||||
|
echo "OK\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fixupGroups()
|
||||||
|
{
|
||||||
|
// Do a separate DB connection
|
||||||
|
|
||||||
|
$sth = $this->dbu->prepare("UPDATE user_group SET ".
|
||||||
|
"fullname = UNHEX(?),".
|
||||||
|
"location = UNHEX(?), ".
|
||||||
|
"description = UNHEX(?) ".
|
||||||
|
"WHERE id = ?");
|
||||||
|
|
||||||
|
if (PEAR::isError($sth)) {
|
||||||
|
echo "ERROR: " . $sth->getMessage() . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'SELECT id, fullname, location, description FROM user_group ' .
|
||||||
|
'WHERE LENGTH(fullname) != CHAR_LENGTH(fullname) '.
|
||||||
|
'OR LENGTH(location) != CHAR_LENGTH(location) '.
|
||||||
|
'OR LENGTH(description) != CHAR_LENGTH(description) ';
|
||||||
|
'AND modified < "'.$this->max_date.'" '.
|
||||||
|
'ORDER BY modified DESC';
|
||||||
|
|
||||||
|
$rn = $this->dbl->query($sql);
|
||||||
|
|
||||||
|
if (PEAR::isError($rn)) {
|
||||||
|
echo "ERROR: " . $rn->getMessage() . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Number of rows: " . $rn->numRows() . "\n";
|
||||||
|
|
||||||
|
$user_group = array();
|
||||||
|
|
||||||
|
while (DB_OK == $rn->fetchInto($user_group)) {
|
||||||
|
|
||||||
|
$id = ($user_group[0])+0;
|
||||||
|
$fullname = bin2hex($user_group[1]);
|
||||||
|
$location = bin2hex($user_group[2]);
|
||||||
|
$description = bin2hex($user_group[3]);
|
||||||
|
|
||||||
|
echo "$id...";
|
||||||
|
|
||||||
|
$result =& $this->dbu->execute($sth, array($fullname, $location, $description, $id));
|
||||||
|
|
||||||
|
if (PEAR::isError($result)) {
|
||||||
|
echo "ERROR: " . $result->getMessage() . "\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cnt = $this->dbu->affectedRows();
|
||||||
|
|
||||||
|
if ($cnt != 1) {
|
||||||
|
echo "ERROR: 0 rows affected\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_group = User_group::staticGet('id', $id);
|
||||||
|
$user_group->decache();
|
||||||
|
$user_group->free();
|
||||||
|
|
||||||
|
echo "OK\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fixupMessages() {
|
||||||
|
|
||||||
|
// Do a separate DB connection
|
||||||
|
|
||||||
|
$sth = $this->dbu->prepare("UPDATE message SET content = UNHEX(?), rendered = UNHEX(?) WHERE id = ?");
|
||||||
|
|
||||||
|
if (PEAR::isError($sth)) {
|
||||||
|
echo "ERROR: " . $sth->getMessage() . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'SELECT id, content, rendered FROM message ' .
|
||||||
|
'WHERE LENGTH(content) != CHAR_LENGTH(content) '.
|
||||||
|
'AND modified < "'.$this->max_date.'" '.
|
||||||
|
'ORDER BY id DESC';
|
||||||
|
|
||||||
|
$rn = $this->dbl->query($sql);
|
||||||
|
|
||||||
|
if (PEAR::isError($rn)) {
|
||||||
|
echo "ERROR: " . $rn->getMessage() . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Number of rows: " . $rn->numRows() . "\n";
|
||||||
|
|
||||||
|
$message = array();
|
||||||
|
|
||||||
|
while (DB_OK == $rn->fetchInto($message)) {
|
||||||
|
|
||||||
|
$id = ($message[0])+0;
|
||||||
|
$content = bin2hex($message[1]);
|
||||||
|
$rendered = bin2hex($message[2]);
|
||||||
|
|
||||||
|
echo "$id...";
|
||||||
|
|
||||||
|
$result =& $this->dbu->execute($sth, array($content, $rendered, $id));
|
||||||
|
|
||||||
|
if (PEAR::isError($result)) {
|
||||||
|
echo "ERROR: " . $result->getMessage() . "\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cnt = $this->dbu->affectedRows();
|
||||||
|
|
||||||
|
if ($cnt != 1) {
|
||||||
|
echo "ERROR: 0 rows affected\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = Message::staticGet('id', $id);
|
||||||
|
$message->decache();
|
||||||
|
$message->free();
|
||||||
|
|
||||||
|
echo "OK\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$max_date = ($argc > 1) ? $argv[1] : null;
|
||||||
|
$max_id = ($argc > 2) ? $argv[2] : null;
|
||||||
|
$min_id = ($argc > 3) ? $argv[3] : null;
|
||||||
|
|
||||||
|
$fixer = new UTF8FixerUpper(array('max_date' => $max_date,
|
||||||
|
'max_notice' => $max_id,
|
||||||
|
'min_notice' => $min_id));
|
||||||
|
|
||||||
|
$fixer->fixup();
|
||||||
|
|
@ -25,7 +25,6 @@
|
|||||||
* daemon names.
|
* daemon names.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
# Abort if called from a web server
|
# Abort if called from a web server
|
||||||
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||||
print "This script must be run from the command line\n";
|
print "This script must be run from the command line\n";
|
||||||
@ -51,5 +50,4 @@ echo "ombqueuehandler.php ";
|
|||||||
echo "twitterqueuehandler.php ";
|
echo "twitterqueuehandler.php ";
|
||||||
echo "facebookqueuehandler.php ";
|
echo "facebookqueuehandler.php ";
|
||||||
echo "pingqueuehandler.php ";
|
echo "pingqueuehandler.php ";
|
||||||
echo "inboxqueuehandler.php ";
|
|
||||||
echo "smsqueuehandler.php ";
|
echo "smsqueuehandler.php ";
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
/*
|
|
||||||
* Laconica - a distributed open-source microblogging tool
|
|
||||||
* Copyright (C) 2008,2009 Control Yourself, 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/queuehandler.php');
|
|
||||||
|
|
||||||
set_error_handler('common_error_handler');
|
|
||||||
|
|
||||||
class InboxQueueHandler extends QueueHandler
|
|
||||||
{
|
|
||||||
function transport()
|
|
||||||
{
|
|
||||||
return 'inbox';
|
|
||||||
}
|
|
||||||
|
|
||||||
function start() {
|
|
||||||
$this->log(LOG_INFO, "INITIALIZE");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_notice($notice)
|
|
||||||
{
|
|
||||||
$this->log(LOG_INFO, "Distributing notice to inboxes for $notice->id");
|
|
||||||
$notice->addToInboxes();
|
|
||||||
$notice->blowSubsCache();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 InboxQueueHandler($id);
|
|
||||||
|
|
||||||
$handler->runOnce();
|
|
@ -1,70 +0,0 @@
|
|||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
/*
|
|
||||||
* Laconica - a distributed open-source microblogging tool
|
|
||||||
* Copyright (C) 2008,2009 Control Yourself, 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/queuehandler.php');
|
|
||||||
|
|
||||||
set_error_handler('common_error_handler');
|
|
||||||
|
|
||||||
class MemcachedQueueHandler extends QueueHandler
|
|
||||||
{
|
|
||||||
function transport()
|
|
||||||
{
|
|
||||||
return 'memcache';
|
|
||||||
}
|
|
||||||
|
|
||||||
function start() {
|
|
||||||
$this->log(LOG_INFO, "INITIALIZE");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_notice($notice)
|
|
||||||
{
|
|
||||||
// XXX: fork here
|
|
||||||
$this->log(LOG_INFO, "Blowing memcached for $notice->id");
|
|
||||||
$notice->blowCaches();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 MemcachedQueueHandler($id);
|
|
||||||
|
|
||||||
$handler->runOnce();
|
|
@ -24,8 +24,7 @@ SDIR=`dirname $0`
|
|||||||
DIR=`php $SDIR/getpiddir.php`
|
DIR=`php $SDIR/getpiddir.php`
|
||||||
|
|
||||||
for f in jabberhandler ombhandler publichandler smshandler pinghandler \
|
for f in jabberhandler ombhandler publichandler smshandler pinghandler \
|
||||||
xmppconfirmhandler xmppdaemon twitterhandler facebookhandler \
|
xmppconfirmhandler xmppdaemon twitterhandler facebookhandler; do
|
||||||
memcachehandler inboxhandler twitterstatusfetcher; do
|
|
||||||
|
|
||||||
FILES="$DIR/$f.*.pid"
|
FILES="$DIR/$f.*.pid"
|
||||||
for ff in "$FILES" ; do
|
for ff in "$FILES" ; do
|
||||||
|
@ -452,6 +452,21 @@ float:left;
|
|||||||
font-size:1.3em;
|
font-size:1.3em;
|
||||||
margin-bottom:7px;
|
margin-bottom:7px;
|
||||||
}
|
}
|
||||||
|
#form_notice label[for=notice_data-attach] {
|
||||||
|
text-indent:-9999px;
|
||||||
|
}
|
||||||
|
#form_notice label[for=notice_data-attach],
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
position:absolute;
|
||||||
|
top:25px;
|
||||||
|
right:49px;
|
||||||
|
width:16px;
|
||||||
|
height:16px;
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
text-indent:-279px;
|
||||||
|
}
|
||||||
#form_notice #notice_submit label {
|
#form_notice #notice_submit label {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
@ -855,20 +870,6 @@ display:inline-block;
|
|||||||
text-transform:lowercase;
|
text-transform:lowercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice .attachment {
|
|
||||||
position:relative;
|
|
||||||
}
|
|
||||||
.notice .attachment img {
|
|
||||||
position:absolute;
|
|
||||||
top:18px;
|
|
||||||
left:0;
|
|
||||||
z-index:99;
|
|
||||||
}
|
|
||||||
#shownotice .notice .attachment img {
|
|
||||||
position:static;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.notice-options {
|
.notice-options {
|
||||||
position:relative;
|
position:relative;
|
||||||
font-size:0.95em;
|
font-size:0.95em;
|
||||||
@ -936,6 +937,75 @@ padding:0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.notice .attachment {
|
||||||
|
position:relative;
|
||||||
|
padding-left:16px;
|
||||||
|
}
|
||||||
|
#attachments .attachment {
|
||||||
|
padding-left:0;
|
||||||
|
}
|
||||||
|
.notice .attachment img {
|
||||||
|
position:absolute;
|
||||||
|
top:18px;
|
||||||
|
left:0;
|
||||||
|
z-index:99;
|
||||||
|
}
|
||||||
|
#shownotice .notice .attachment img {
|
||||||
|
position:static;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachments {
|
||||||
|
clear:both;
|
||||||
|
float:left;
|
||||||
|
width:100%;
|
||||||
|
margin-top:18px;
|
||||||
|
}
|
||||||
|
#attachments dt {
|
||||||
|
font-weight:bold;
|
||||||
|
font-size:1.3em;
|
||||||
|
margin-bottom:4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachments ol li {
|
||||||
|
margin-bottom:18px;
|
||||||
|
list-style-type:decimal;
|
||||||
|
float:left;
|
||||||
|
clear:both;
|
||||||
|
}
|
||||||
|
|
||||||
|
#jOverlayContent,
|
||||||
|
#jOverlayContent #content,
|
||||||
|
#jOverlayContent #content_inner {
|
||||||
|
width: auto !important;
|
||||||
|
margin-bottom:0;
|
||||||
|
}
|
||||||
|
#jOverlayContent #content {
|
||||||
|
padding:11px;
|
||||||
|
min-height:auto;
|
||||||
|
}
|
||||||
|
#jOverlayContent .external span {
|
||||||
|
display:block;
|
||||||
|
margin-bottom:11px;
|
||||||
|
}
|
||||||
|
#jOverlayContent button {
|
||||||
|
position:absolute;
|
||||||
|
top:0;
|
||||||
|
right:0;
|
||||||
|
width:29px;
|
||||||
|
height:29px;
|
||||||
|
text-align:center;
|
||||||
|
font-weight:bold;
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
#jOverlayContent h1 {
|
||||||
|
max-width:475px;
|
||||||
|
}
|
||||||
|
#jOverlayContent #content {
|
||||||
|
border-radius:7px;
|
||||||
|
-moz-border-radius:7px;
|
||||||
|
-webkit-border-radius:7px;
|
||||||
|
}
|
||||||
|
|
||||||
#usergroups #new_group {
|
#usergroups #new_group {
|
||||||
float: left;
|
float: left;
|
||||||
margin-right: 2em;
|
margin-right: 2em;
|
||||||
@ -1182,6 +1252,7 @@ width:33%;
|
|||||||
}
|
}
|
||||||
#settings_design_color .form_data label {
|
#settings_design_color .form_data label {
|
||||||
float:none;
|
float:none;
|
||||||
|
display:block;
|
||||||
}
|
}
|
||||||
#settings_design_color .form_data .swatch {
|
#settings_design_color .form_data .swatch {
|
||||||
padding:11px;
|
padding:11px;
|
||||||
|
@ -30,3 +30,12 @@ margin-right:4px;
|
|||||||
.entity_profile {
|
.entity_profile {
|
||||||
width:64%;
|
width:64%;
|
||||||
}
|
}
|
||||||
|
.notice {
|
||||||
|
z-index:1;
|
||||||
|
}
|
||||||
|
.notice:hover {
|
||||||
|
z-index:9999;
|
||||||
|
}
|
||||||
|
.notice .thumbnail img {
|
||||||
|
z-index:9999;
|
||||||
|
}
|
BIN
theme/base/images/icons/twotone/green/clip-01.gif
Normal file
BIN
theme/base/images/icons/twotone/green/clip-01.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 B |
BIN
theme/base/images/icons/twotone/green/clip-02.gif
Normal file
BIN
theme/base/images/icons/twotone/green/clip-02.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 70 B |
@ -446,6 +446,27 @@ float:left;
|
|||||||
font-size:1.3em;
|
font-size:1.3em;
|
||||||
margin-bottom:7px;
|
margin-bottom:7px;
|
||||||
}
|
}
|
||||||
|
#form_notice label {
|
||||||
|
display:block;
|
||||||
|
float:left;
|
||||||
|
font-size:1.3em;
|
||||||
|
margin-bottom:7px;
|
||||||
|
}
|
||||||
|
#form_notice label[for=notice_data-attach] {
|
||||||
|
text-indent:-9999px;
|
||||||
|
}
|
||||||
|
#form_notice label[for=notice_data-attach],
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
position:absolute;
|
||||||
|
top:25px;
|
||||||
|
right:49px;
|
||||||
|
width:16px;
|
||||||
|
height:16px;
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
text-indent:-279px;
|
||||||
|
}
|
||||||
#form_notice #notice_submit label {
|
#form_notice #notice_submit label {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,13 @@ color:#333;
|
|||||||
#form_notice.warning #notice_text-count {
|
#form_notice.warning #notice_text-count {
|
||||||
color:#000;
|
color:#000;
|
||||||
}
|
}
|
||||||
|
#form_notice label[for=notice_data-attach] {
|
||||||
|
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
|
||||||
|
}
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
|
||||||
#form_notice.processing #notice_action-submit {
|
#form_notice.processing #notice_action-submit {
|
||||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||||
cursor:wait;
|
cursor:wait;
|
||||||
|
@ -82,6 +82,13 @@ color:#333;
|
|||||||
#form_notice.warning #notice_text-count {
|
#form_notice.warning #notice_text-count {
|
||||||
color:#000;
|
color:#000;
|
||||||
}
|
}
|
||||||
|
#form_notice label[for=notice_data-attach] {
|
||||||
|
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
|
||||||
|
}
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
|
||||||
#form_notice.processing #notice_action-submit {
|
#form_notice.processing #notice_action-submit {
|
||||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||||
cursor:wait;
|
cursor:wait;
|
||||||
@ -175,6 +182,12 @@ background-image:url(../../base/images/icons/twotone/green/shield.gif);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* NOTICES */
|
/* NOTICES */
|
||||||
|
.notice .attachment {
|
||||||
|
background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no-repeat 0 45%;
|
||||||
|
}
|
||||||
|
#attachments .attachment {
|
||||||
|
background:none;
|
||||||
|
}
|
||||||
.notice-options .notice_reply a,
|
.notice-options .notice_reply a,
|
||||||
.notice-options form input.submit {
|
.notice-options form input.submit {
|
||||||
background-color:transparent;
|
background-color:transparent;
|
||||||
|
@ -82,6 +82,13 @@ color:#333;
|
|||||||
#form_notice.warning #notice_text-count {
|
#form_notice.warning #notice_text-count {
|
||||||
color:#000;
|
color:#000;
|
||||||
}
|
}
|
||||||
|
#form_notice label[for=notice_data-attach] {
|
||||||
|
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
|
||||||
|
}
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
|
||||||
#form_notice.processing #notice_action-submit {
|
#form_notice.processing #notice_action-submit {
|
||||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||||
cursor:wait;
|
cursor:wait;
|
||||||
@ -175,6 +182,12 @@ background-image:url(../../base/images/icons/twotone/green/shield.gif);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* NOTICES */
|
/* NOTICES */
|
||||||
|
.notice .attachment {
|
||||||
|
background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no-repeat 0 45%;
|
||||||
|
}
|
||||||
|
#attachments .attachment {
|
||||||
|
background:none;
|
||||||
|
}
|
||||||
.notice-options .notice_reply a,
|
.notice-options .notice_reply a,
|
||||||
.notice-options form input.submit {
|
.notice-options form input.submit {
|
||||||
background-color:transparent;
|
background-color:transparent;
|
||||||
|
Loading…
Reference in New Issue
Block a user