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/*
|
||||
files/*
|
||||
file/*
|
||||
_darcs/*
|
||||
logs/*
|
||||
config.php
|
||||
|
@ -16,3 +17,8 @@ dataobject.ini
|
|||
.buildpath
|
||||
.project
|
||||
.settings
|
||||
TODO.rym
|
||||
config-*.php
|
||||
good-config.php
|
||||
lac08.log
|
||||
php.log
|
||||
|
|
125
README
125
README
|
@ -2,8 +2,8 @@
|
|||
README
|
||||
------
|
||||
|
||||
Laconica 0.7.3 ("You Are The Everything")
|
||||
7 April 2009
|
||||
Laconica 0.7.4 ("Can't Get There From Here")
|
||||
29 May 2009
|
||||
|
||||
This is the README file for Laconica, the Open Source microblogging
|
||||
platform. It includes installation instructions, descriptions of
|
||||
|
@ -71,29 +71,29 @@ for additional terms.
|
|||
New this version
|
||||
================
|
||||
|
||||
This is a minor bug-fix and feature release since version 0.7.2.1,
|
||||
released Mar 11 2009. Notable changes this version:
|
||||
This is a minor bug-fix and feature release since version 0.7.3,
|
||||
released Apr 4 2009. Notable changes this version:
|
||||
|
||||
- A plugin to allow a templating language for customization
|
||||
- A plugin for Piwik Analytics engine
|
||||
- A bookmarklet for posting a notice about a Web page you're reading
|
||||
- A welcome notice ('welcomebot') and default subscription for new users
|
||||
- Support for SSL for some or all pages on the site
|
||||
- Better handling of empty notice lists on many pages
|
||||
- Major improvements to the Twitter friend-sync offline processing
|
||||
- subscribers, subscriptions, groups are listed on the Personal page.
|
||||
- "Invite" link restored to main menu
|
||||
- Better memory handling in FOAF output
|
||||
- Fix for SUP support (FriendFeed)
|
||||
- Correct and intelligent redirect HTTP status codes
|
||||
- Fix DB collations for search and sort
|
||||
- Better H1s and Titles using user full names
|
||||
- Fixes to make the linkback plugin operational
|
||||
- Better indication that a notice is being published by Ajax (spinner)
|
||||
- Better and unified Atom output
|
||||
- Hiding "register" and "join now" messages when site is closed
|
||||
- ping, twitter and facebook queuehandlers working better
|
||||
- Updated RPM spec
|
||||
- Improved handling of UTF-8 characters. The new code is *not* backwards
|
||||
compatible by default; see "Upgrading" below for instructions on
|
||||
converting existing databases to the correct character set.
|
||||
- Unroll joins for large queries. This greatly enhanced database
|
||||
performance -- up to 50x for some queries -- at the expense of making
|
||||
an extra DB hit for some queries.
|
||||
- Added an optional plugin to use WikiHashtags
|
||||
(http://hashtags.wikia.com/) for the sidebar on hashtag pages.
|
||||
- Optimized Twitter friend synchronization.
|
||||
- Better error handling for Ajax posting of notices, including
|
||||
HTTP errors and timeouts.
|
||||
- Experimental Comet plugin -- supports the cometd and the Bayeux
|
||||
protocol. Using this plugin, you can show "real time" updates on the
|
||||
public and tag pages. However, server configuration is complex.
|
||||
- If queues are enabled, update inboxes and memcached off-line. Speeds
|
||||
up posting considerably.
|
||||
- Correctly shorten links posted through XMPP.
|
||||
- <link> elements for pagination, supported by some browsers like Opera.
|
||||
- Corrected date format in search API.
|
||||
- Made the public XRDS file work correctly.
|
||||
|
||||
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
|
||||
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
|
||||
may have to unpack the tarball on your local computer and FTP the
|
||||
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
|
||||
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
|
||||
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
|
||||
=========
|
||||
|
||||
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
|
||||
tracking the "git" version of the software, you will probably want
|
||||
to upgrade and keep your existing data. There is no automated upgrade
|
||||
procedure in 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.
|
||||
|
||||
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
|
||||
'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
|
||||
=====================
|
||||
|
||||
|
@ -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
|
||||
requests to go to the 'database' (master) server, you'll need
|
||||
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
|
||||
------
|
||||
|
@ -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
|
||||
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
|
||||
===============
|
||||
|
||||
|
@ -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
|
||||
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
|
||||
"Notice inboxes" section above.
|
||||
|
||||
|
@ -1265,6 +1330,8 @@ if anyone's been overlooked in error.
|
|||
* Ken Sedgwick
|
||||
* Brian Hendrickson
|
||||
* Tobias Diekershoff
|
||||
* Dan Moore
|
||||
* Fil
|
||||
|
||||
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,
|
||||
|
|
|
@ -67,6 +67,7 @@ class ApiAction extends Action
|
|||
$this->process_command();
|
||||
} else {
|
||||
# basic authentication failed
|
||||
common_log(LOG_WARNING, "Failed API auth attempt, nickname: $nickname.");
|
||||
$this->show_basic_auth_error();
|
||||
}
|
||||
}
|
||||
|
@ -143,8 +144,8 @@ class ApiAction extends Action
|
|||
}
|
||||
|
||||
if (in_array($fullname, $bareauth)) {
|
||||
# bareauth: only needs auth if without an argument
|
||||
if ($this->api_arg) {
|
||||
# bareauth: only needs auth if without an argument or query param specifying user
|
||||
if ($this->api_arg || $this->arg('id') || is_numeric($this->arg('user_id')) || $this->arg('screen_name')) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
|
|
|
@ -179,14 +179,14 @@ class ConversationTree extends NoticeList
|
|||
|
||||
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
||||
$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)) {
|
||||
$rootid = $this->tree['root'][0];
|
||||
$this->showNoticePlus($rootid);
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('ol');
|
||||
$this->out->elementEnd('div');
|
||||
|
||||
return $cnt;
|
||||
|
@ -215,13 +215,13 @@ class ConversationTree extends NoticeList
|
|||
if (array_key_exists($id, $this->tree)) {
|
||||
$children = $this->tree[$id];
|
||||
|
||||
$this->out->elementStart('ul', array('class' => 'notices'));
|
||||
$this->out->elementStart('ol', array('class' => 'notices'));
|
||||
|
||||
foreach ($children as $child) {
|
||||
$this->showNoticePlus($child);
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('ol');
|
||||
}
|
||||
|
||||
$this->out->elementEnd('li');
|
||||
|
|
|
@ -68,7 +68,7 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$this->elementStart('form', array('method' => 'POST',
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_settings_design',
|
||||
'class' => 'form_settings',
|
||||
'action' =>
|
||||
|
@ -80,8 +80,8 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||
$this->element('legend', null, _('Change background image'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->element('label', array('for' => 'design_ background-image_file'),
|
||||
_('Upload file'));
|
||||
$this->element('label', array('for' => 'design_background-image_file'),
|
||||
_('Upload file'));
|
||||
$this->element('input', array('name' => 'design_background-image_file',
|
||||
'type' => 'file',
|
||||
'id' => 'design_background-image_file'));
|
||||
|
|
|
@ -115,7 +115,7 @@ class FacebookhomeAction extends FacebookAction
|
|||
$flink->foreign_id = $this->fbuid;
|
||||
$flink->service = FACEBOOK_SERVICE;
|
||||
$flink->created = common_sql_now();
|
||||
$flink->set_flags(true, false, false);
|
||||
$flink->set_flags(true, false, false, false);
|
||||
|
||||
$flink_id = $flink->insert();
|
||||
|
||||
|
@ -138,9 +138,6 @@ class FacebookhomeAction extends FacebookAction
|
|||
|
||||
function setDefaults()
|
||||
{
|
||||
// A default prefix string for notices
|
||||
$this->facebook->api_client->data_setUserPreference(
|
||||
FACEBOOK_NOTICE_PREFIX, 'dented: ');
|
||||
$this->facebook->api_client->data_setUserPreference(
|
||||
FACEBOOK_PROMPTED_UPDATE_PREF, 'false');
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
* 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');
|
||||
|
||||
|
@ -89,16 +91,6 @@ class FacebookinviteAction extends FacebookAction
|
|||
|
||||
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')) .
|
||||
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['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['bypass'] = 'cancel';
|
||||
|
||||
$this->element('fb:multi-friend-selector', $multi_params);
|
||||
|
||||
$this->elementEnd('fb:request-form');
|
||||
|
||||
$this->element('h2', null, sprintf(_('Friends already using %s:'),
|
||||
common_config('site', 'name')));
|
||||
$this->elementStart('ul', array('id' => 'facebook-friends'));
|
||||
if ($exclude_ids) {
|
||||
|
||||
foreach ($exclude_ids as $friend) {
|
||||
$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->element('h2', null, sprintf(_('Friends already using %s:'),
|
||||
common_config('site', 'name')));
|
||||
$this->elementStart('ul', array('id' => 'facebook-friends'));
|
||||
|
||||
foreach ($exclude_ids as $friend) {
|
||||
$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()
|
||||
|
|
|
@ -55,7 +55,7 @@ class FacebooksettingsAction extends FacebookAction
|
|||
$prefix = $this->trimmed('prefix');
|
||||
|
||||
$original = clone($this->flink);
|
||||
$this->flink->set_flags($noticesync, $replysync, false);
|
||||
$this->flink->set_flags($noticesync, $replysync, false, false);
|
||||
$result = $this->flink->update($original);
|
||||
|
||||
$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)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('Not logged in.'));
|
||||
} 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
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->clientError(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->saveNewNotice();
|
||||
} 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
|
||||
*
|
||||
|
@ -131,7 +159,6 @@ class NewnoticeAction extends Action
|
|||
$this->clientError(_('No content!'));
|
||||
} else {
|
||||
$content_shortened = common_shorten_links($content);
|
||||
|
||||
if (mb_strlen($content_shortened) > 140) {
|
||||
$this->clientError(_('That\'s too long. '.
|
||||
'Max notice size is 140 chars.'));
|
||||
|
@ -158,17 +185,53 @@ class NewnoticeAction extends Action
|
|||
$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,
|
||||
($replyto == 'false') ? null : $replyto);
|
||||
|
||||
if (is_string($notice)) {
|
||||
$this->clientError($notice);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($mimetype)) {
|
||||
$this->storeFile($notice, $mimetype);
|
||||
}
|
||||
$this->saveUrls($notice);
|
||||
|
||||
common_broadcast_notice($notice);
|
||||
|
||||
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
|
||||
*
|
||||
* follow redirects and save all available file information
|
||||
|
@ -203,7 +293,7 @@ class NewnoticeAction extends Action
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
function saveUrls($notice) {
|
||||
function saveUrls($notice, $uploaded = null) {
|
||||
common_replace_urls_callback($notice->content, array($this, 'saveUrl'), $notice->id);
|
||||
}
|
||||
|
||||
|
@ -316,3 +406,4 @@ class NewnoticeAction extends Action
|
|||
$nli->show();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ class ShownoticeAction extends Action
|
|||
|
||||
function lastModified()
|
||||
{
|
||||
return max(strtotime($this->notice->created),
|
||||
return max(strtotime($this->notice->modified),
|
||||
strtotime($this->profile->modified),
|
||||
($this->avatar) ? strtotime($this->avatar->modified) : 0);
|
||||
}
|
||||
|
@ -208,10 +208,10 @@ class ShownoticeAction extends Action
|
|||
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('ul', array('class' => 'notices'));
|
||||
$this->elementStart('ol', array('class' => 'notices xoxo'));
|
||||
$nli = new NoticeListItem($this->notice, $this);
|
||||
$nli->show();
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('ol');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -98,9 +98,31 @@ class TwitapiaccountAction extends TwitterapiAction
|
|||
$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)
|
||||
{
|
||||
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');
|
||||
$since = $this->arg('since');
|
||||
$since_id = $this->arg('since_id');
|
||||
$before_id = $this->arg('before_id');
|
||||
$max_id = $this->arg('max_id');
|
||||
|
||||
$page = $this->arg('page');
|
||||
|
||||
|
@ -74,8 +74,8 @@ class Twitapidirect_messagesAction extends TwitterapiAction
|
|||
$link = $server . $user->nickname . '/outbox';
|
||||
}
|
||||
|
||||
if ($before_id) {
|
||||
$message->whereAdd("id < $before_id");
|
||||
if ($max_id) {
|
||||
$message->whereAdd("id <= $max_id");
|
||||
}
|
||||
|
||||
if ($since_id) {
|
||||
|
|
|
@ -45,22 +45,21 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
|
||||
$page = $this->arg('page');
|
||||
$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) {
|
||||
$page = 1;
|
||||
}
|
||||
if (!$since_id) {
|
||||
$since_id = 0;
|
||||
}
|
||||
if (!$before_id) {
|
||||
$before_id = 0;
|
||||
if (!$max_id) {
|
||||
$max_id = 0;
|
||||
}
|
||||
|
||||
$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) {
|
||||
|
||||
|
@ -97,7 +96,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
$since_id = $this->arg('since_id');
|
||||
$count = $this->arg('count');
|
||||
$page = $this->arg('page');
|
||||
$before_id = $this->arg('before_id');
|
||||
$max_id = $this->arg('max_id');
|
||||
|
||||
if (!$page) {
|
||||
$page = 1;
|
||||
|
@ -111,9 +110,8 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
$since_id = 0;
|
||||
}
|
||||
|
||||
// NOTE: before_id is an extension to Twitter API -- TB
|
||||
if (!$before_id) {
|
||||
$before_id = 0;
|
||||
if (!$max_id) {
|
||||
$max_id = 0;
|
||||
}
|
||||
|
||||
$since = strtotime($this->arg('since'));
|
||||
|
@ -133,7 +131,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
$link = common_local_url('all', array('nickname' => $user->nickname));
|
||||
$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']) {
|
||||
case 'xml':
|
||||
|
@ -184,7 +182,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
$since = $this->arg('since');
|
||||
$since_id = $this->arg('since_id');
|
||||
$page = $this->arg('page');
|
||||
$before_id = $this->arg('before_id');
|
||||
$max_id = $this->arg('max_id');
|
||||
|
||||
if (!$page) {
|
||||
$page = 1;
|
||||
|
@ -198,9 +196,8 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
$since_id = 0;
|
||||
}
|
||||
|
||||
// NOTE: before_id is an extensions to Twitter API -- TB
|
||||
if (!$before_id) {
|
||||
$before_id = 0;
|
||||
if (!$max_id) {
|
||||
$max_id = 0;
|
||||
}
|
||||
|
||||
$since = strtotime($this->arg('since'));
|
||||
|
@ -220,7 +217,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
|
||||
# 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']) {
|
||||
case 'xml':
|
||||
|
@ -353,7 +350,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
$count = $this->arg('count');
|
||||
$page = $this->arg('page');
|
||||
$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);
|
||||
$this->auth_user = $apidata['user'];
|
||||
|
@ -380,15 +377,14 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||
$since_id = 0;
|
||||
}
|
||||
|
||||
// NOTE: before_id is an extension to Twitter API -- TB
|
||||
if (!$before_id) {
|
||||
$before_id = 0;
|
||||
if (!$max_id) {
|
||||
$max_id = 0;
|
||||
}
|
||||
|
||||
$since = strtotime($this->arg('since'));
|
||||
|
||||
$notice = $user->getReplies((($page-1)*20),
|
||||
$count, $since_id, $before_id, $since);
|
||||
$count, $since_id, $max_id, $since);
|
||||
$notices = array();
|
||||
|
||||
while ($notice->fetch()) {
|
||||
|
|
|
@ -33,102 +33,53 @@ class TwitapiusersAction extends TwitterapiAction
|
|||
return;
|
||||
}
|
||||
|
||||
$user = null;
|
||||
$email = $this->arg('email');
|
||||
$user_id = $this->arg('user_id');
|
||||
$user = null;
|
||||
$email = $this->arg('email');
|
||||
$user_id = $this->arg('user_id');
|
||||
|
||||
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'];
|
||||
}
|
||||
// XXX: email field deprecated in Twitter's API
|
||||
|
||||
if (!$user) {
|
||||
// XXX: Twitter returns a random(?) user instead of throwing and err! -- Zach
|
||||
$this->client_error(_('Not found.'), 404, $apidata['content-type']);
|
||||
return;
|
||||
}
|
||||
// XXX: Also: need to add screen_name param
|
||||
|
||||
$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) {
|
||||
common_server_error(_('User has no profile.'));
|
||||
return;
|
||||
}
|
||||
if (!$user) {
|
||||
$this->client_error(_('Not found.'), 404, $apidata['content-type']);
|
||||
return;
|
||||
}
|
||||
|
||||
$twitter_user = $this->twitter_user_array($profile, true);
|
||||
$profile = $user->getProfile();
|
||||
|
||||
// Add in extended user fields offered up by this method
|
||||
$twitter_user['created_at'] = $this->date_twitter($profile->created);
|
||||
if (!$profile) {
|
||||
common_server_error(_('User has no profile.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$subbed = DB_DataObject::factory('subscription');
|
||||
$subbed->subscriber = $profile->id;
|
||||
$subbed_count = (int) $subbed->count() - 1;
|
||||
$twitter_user = $this->twitter_user_array($profile, true);
|
||||
|
||||
$notices = DB_DataObject::factory('notice');
|
||||
$notices->profile_id = $profile->id;
|
||||
$notice_count = (int) $notices->count();
|
||||
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 {
|
||||
|
||||
$twitter_user['friends_count'] = (is_int($subbed_count)) ? $subbed_count : 0;
|
||||
$twitter_user['statuses_count'] = (is_int($notice_count)) ? $notice_count : 0;
|
||||
|
||||
// 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).
|
||||
// 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');
|
||||
print 'Authorized';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ class Fave extends Memcached_DataObject
|
|||
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();
|
||||
|
||||
|
@ -59,8 +59,8 @@ class Fave extends Memcached_DataObject
|
|||
$fav->whereAdd('notice_id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($before_id != 0) {
|
||||
$fav->whereAdd('notice_id < ' . $before_id);
|
||||
if ($max_id != 0) {
|
||||
$fav->whereAdd('notice_id <= ' . $max_id);
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
|
|
|
@ -120,4 +120,30 @@ class File extends Memcached_DataObject
|
|||
File_to_post::processNew($file_id, $notice_id);
|
||||
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->orderBy('len');
|
||||
$file->find(true);
|
||||
if (!empty($file->id)) {
|
||||
if (!empty($file->url) && (strlen($file->url) < strlen($long_url))) {
|
||||
return $file->url;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ class Foreign_link extends Memcached_DataObject
|
|||
|
||||
public $__table = 'foreign_link'; // table name
|
||||
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 $credentials; // varchar(255)
|
||||
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);
|
||||
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);
|
||||
|
||||
$final = common_shorten_links($content);
|
||||
|
||||
if (!$profile) {
|
||||
common_log(LOG_ERR, '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.');
|
||||
}
|
||||
|
||||
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.');
|
||||
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->created = common_sql_now();
|
||||
$notice->content = $content;
|
||||
$notice->rendered = common_render_content($content, $notice);
|
||||
$notice->content = $final;
|
||||
$notice->rendered = common_render_content($final, $notice);
|
||||
$notice->source = $source;
|
||||
$notice->uri = $uri;
|
||||
|
||||
|
@ -202,13 +204,9 @@ class Notice extends Memcached_DataObject
|
|||
|
||||
$notice->saveReplies();
|
||||
$notice->saveTags();
|
||||
$notice->saveGroups();
|
||||
|
||||
if (common_config('queue', 'enabled')) {
|
||||
$notice->addToAuthorInbox();
|
||||
} else {
|
||||
$notice->addToInboxes();
|
||||
}
|
||||
$notice->addToInboxes();
|
||||
$notice->saveGroups();
|
||||
|
||||
$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
|
||||
# XXX: someone clever could prepend instead of clearing the cache
|
||||
|
||||
if (common_config('memcached', 'enabled')) {
|
||||
if (common_config('queue', 'enabled')) {
|
||||
$notice->blowAuthorCaches();
|
||||
} else {
|
||||
$notice->blowCaches();
|
||||
}
|
||||
}
|
||||
$notice->blowCaches();
|
||||
|
||||
return $notice;
|
||||
}
|
||||
|
@ -277,6 +269,18 @@ class Notice extends Memcached_DataObject
|
|||
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() {
|
||||
$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);
|
||||
|
@ -297,17 +301,6 @@ class Notice extends Memcached_DataObject
|
|||
$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)
|
||||
{
|
||||
$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
|
||||
# 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')) {
|
||||
|
||||
# Skip the cache if this is a since, since_id or before_id qry
|
||||
if ($since_id > 0 || $before_id > 0 || $since) {
|
||||
return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since);
|
||||
# Skip the cache if this is a since, since_id or max_id qry
|
||||
if ($since_id > 0 || $max_id > 0 || $since) {
|
||||
return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since);
|
||||
} else {
|
||||
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;
|
||||
$needWhere = true;
|
||||
|
@ -480,7 +473,7 @@ class Notice extends Memcached_DataObject
|
|||
$qry .= ' notice.id > ' . $since_id;
|
||||
}
|
||||
|
||||
if ($before_id > 0) {
|
||||
if ($max_id > 0) {
|
||||
|
||||
if ($needWhere) {
|
||||
$qry .= ' WHERE ';
|
||||
|
@ -489,7 +482,7 @@ class Notice extends Memcached_DataObject
|
|||
$qry .= ' AND ';
|
||||
}
|
||||
|
||||
$qry .= ' notice.id < ' . $before_id;
|
||||
$qry .= ' notice.id <= ' . $max_id;
|
||||
}
|
||||
|
||||
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'),
|
||||
array(),
|
||||
'public',
|
||||
$offset, $limit, $since_id, $before_id, $since);
|
||||
$offset, $limit, $since_id, $max_id, $since);
|
||||
|
||||
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();
|
||||
|
||||
|
@ -681,8 +674,8 @@ class Notice extends Memcached_DataObject
|
|||
$notice->whereAdd('id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($before_id != 0) {
|
||||
$notice->whereAdd('id < ' . $before_id);
|
||||
if ($max_id != 0) {
|
||||
$notice->whereAdd('id <= ' . $max_id);
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
|
@ -726,33 +719,6 @@ class Notice extends Memcached_DataObject
|
|||
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()
|
||||
{
|
||||
$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();
|
||||
|
||||
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) {
|
||||
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);
|
||||
|
|
|
@ -43,15 +43,15 @@ class Notice_inbox extends Memcached_DataObject
|
|||
/* the code above is auto generated do not remove the tag below */
|
||||
###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'),
|
||||
array($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();
|
||||
|
||||
|
@ -61,8 +61,8 @@ class Notice_inbox extends Memcached_DataObject
|
|||
$inbox->whereAdd('notice_id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($before_id != 0) {
|
||||
$inbox->whereAdd('notice_id < ' . $before_id);
|
||||
if ($max_id != 0) {
|
||||
$inbox->whereAdd('notice_id <= ' . $max_id);
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
|
|
|
@ -46,7 +46,7 @@ class Notice_tag extends Memcached_DataObject
|
|||
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();
|
||||
|
||||
|
@ -59,8 +59,8 @@ class Notice_tag extends Memcached_DataObject
|
|||
$nt->whereAdd('notice_id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($before_id != 0) {
|
||||
$nt->whereAdd('notice_id < ' . $before_id);
|
||||
if ($max_id != 0) {
|
||||
$nt->whereAdd('notice_id < ' . $max_id);
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
|
|
|
@ -170,7 +170,7 @@ class Profile extends Memcached_DataObject
|
|||
$ids = Notice::stream(array($this, '_streamDirect'),
|
||||
array(),
|
||||
'profile:notice_ids:' . $this->id,
|
||||
$offset, $limit, $since_id, $before_id, $since);
|
||||
$offset, $limit, $since_id, $max_id, $since);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
@ -225,8 +225,8 @@ class Profile extends Memcached_DataObject
|
|||
$notice->whereAdd('id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($before_id != 0) {
|
||||
$notice->whereAdd('id < ' . $before_id);
|
||||
if ($max_id != 0) {
|
||||
$notice->whereAdd('id <= ' . $max_id);
|
||||
}
|
||||
|
||||
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 */
|
||||
###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'),
|
||||
array($user_id),
|
||||
'reply:stream:' . $user_id,
|
||||
$offset, $limit, $since_id, $before_id, $since);
|
||||
$offset, $limit, $since_id, $max_id, $since);
|
||||
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->profile_id = $user_id;
|
||||
|
@ -40,8 +40,8 @@ class Reply extends Memcached_DataObject
|
|||
$reply->whereAdd('notice_id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($before_id != 0) {
|
||||
$reply->whereAdd('notice_id < ' . $before_id);
|
||||
if ($max_id != 0) {
|
||||
$reply->whereAdd('notice_id < ' . $max_id);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
$ids = Reply::stream($this->id, $offset, $limit, $since_id, $before_id, $since);
|
||||
common_debug("Ids = " . implode(',', $ids));
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ class User_group extends Memcached_DataObject
|
|||
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();
|
||||
|
||||
|
@ -71,8 +71,8 @@ class User_group extends Memcached_DataObject
|
|||
$inbox->whereAdd('notice_id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($before_id != 0) {
|
||||
$inbox->whereAdd('notice_id < ' . $before_id);
|
||||
if ($max_id != 0) {
|
||||
$inbox->whereAdd('notice_id <= ' . $max_id);
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
|
|
|
@ -215,3 +215,11 @@ $config['sphinx']['port'] = 3312;
|
|||
// $config['snapshot']['run'] = 'never';
|
||||
// If you want to report statistics in a cron job instead.
|
||||
// $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 (
|
||||
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),
|
||||
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',
|
||||
|
|
|
@ -2,13 +2,18 @@ INSERT INTO notice_source
|
|||
(code, name, url, created)
|
||||
VALUES
|
||||
('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()),
|
||||
('bti','bti','http://gregkh.github.com/bti/', now()),
|
||||
('cliqset', 'Cliqset', 'http://www.cliqset.com/', 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()),
|
||||
('eventbox','EventBox','http://thecosmicmachine.com/eventbox/ ', now()),
|
||||
('Facebook','Facebook','http://apps.facebook.com/identica/', now()),
|
||||
('feed2omb','feed2omb','http://projects.ciarang.com/p/feed2omb/', now()),
|
||||
('get2gnow', 'get2gnow', 'http://uberchicgeekchick.com/?projects=get2gnow', now()),
|
||||
('gravity', 'Gravity', 'http://mobileways.de/gravity', now()),
|
||||
('Gwibber','Gwibber','http://launchpad.net/gwibber', now()),
|
||||
('HelloTxt','HelloTxt','http://hellotxt.com/', now()),
|
||||
|
@ -28,6 +33,7 @@ VALUES
|
|||
('pingvine','PingVine','http://pingvine.com/', now()),
|
||||
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
||||
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
||||
('qtwitter','qTwitter','http://qtwitter.ayoy.net/', now()),
|
||||
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
||||
('rssdent','rssdent','http://github.com/zcopley/rssdent/tree/master', 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() {
|
||||
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".');
|
||||
return;
|
||||
}
|
||||
|
@ -570,7 +570,7 @@ $.fn.clearForm = function() {
|
|||
$.fn.clearFields = $.fn.clearInputs = function() {
|
||||
return this.each(function() {
|
||||
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 = '';
|
||||
else if (t == 'checkbox' || t == 'radio')
|
||||
this.checked = false;
|
||||
|
|
76
js/util.js
76
js/util.js
|
@ -17,30 +17,6 @@
|
|||
*/
|
||||
|
||||
$(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
|
||||
function counter(event){
|
||||
var maxLength = 140;
|
||||
|
@ -227,6 +203,7 @@ $(document).ready(function(){
|
|||
}
|
||||
}
|
||||
$("#notice_data-text").val("");
|
||||
$("#notice_data-attach").val("");
|
||||
counter();
|
||||
}
|
||||
$("#form_notice").removeClass("processing");
|
||||
|
@ -238,6 +215,7 @@ $(document).ready(function(){
|
|||
$("#form_notice").each(addAjaxHidden);
|
||||
NoticeHover();
|
||||
NoticeReply();
|
||||
NoticeAttachments();
|
||||
});
|
||||
|
||||
|
||||
|
@ -276,3 +254,53 @@ function NoticeReplySet(nick,id) {
|
|||
}
|
||||
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()
|
||||
{
|
||||
$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;
|
||||
$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) {
|
||||
$item = $this->newListItem($attachment);
|
||||
$item->show();
|
||||
}
|
||||
|
||||
$this->out->elementEnd('dd');
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('ol');
|
||||
$this->out->elementEnd('dl');
|
||||
|
||||
return count($att);
|
||||
|
@ -266,6 +267,23 @@ class Attachment extends AttachmentListItem
|
|||
case 'image/jpeg':
|
||||
$this->out->element('img', array('src' => $this->attachment->url, 'alt' => 'alt'));
|
||||
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 {
|
||||
|
|
|
@ -163,6 +163,42 @@ $config =
|
|||
array('run' => 'web',
|
||||
'frequency' => 10000,
|
||||
'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');
|
||||
|
@ -174,6 +210,7 @@ $config['db'] =
|
|||
'require_prefix' => 'classes/',
|
||||
'class_prefix' => '',
|
||||
'mirror' => null,
|
||||
'utf8' => true,
|
||||
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
|
||||
'quote_identifiers' => false,
|
||||
'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?
|
||||
|
||||
require_once('Validate.php');
|
||||
require_once('markdown.php');
|
||||
require_once 'Validate.php';
|
||||
require_once 'markdown.php';
|
||||
|
||||
require_once(INSTALLDIR.'/lib/util.php');
|
||||
require_once(INSTALLDIR.'/lib/action.php');
|
||||
require_once(INSTALLDIR.'/lib/theme.php');
|
||||
require_once(INSTALLDIR.'/lib/mail.php');
|
||||
require_once(INSTALLDIR.'/lib/subs.php');
|
||||
require_once(INSTALLDIR.'/lib/Shorturl_api.php');
|
||||
require_once(INSTALLDIR.'/lib/twitter.php');
|
||||
require_once INSTALLDIR.'/lib/util.php';
|
||||
require_once INSTALLDIR.'/lib/action.php';
|
||||
require_once INSTALLDIR.'/lib/theme.php';
|
||||
require_once INSTALLDIR.'/lib/mail.php';
|
||||
require_once INSTALLDIR.'/lib/subs.php';
|
||||
require_once INSTALLDIR.'/lib/Shorturl_api.php';
|
||||
require_once INSTALLDIR.'/lib/twitter.php';
|
||||
|
||||
require_once(INSTALLDIR.'/lib/clientexception.php');
|
||||
require_once(INSTALLDIR.'/lib/serverexception.php');
|
||||
require_once INSTALLDIR.'/lib/clientexception.php';
|
||||
require_once INSTALLDIR.'/lib/serverexception.php';
|
||||
|
||||
// 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
|
||||
$ts = filemtime(INSTALLDIR.'/theme/base/css/display.css');
|
||||
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts));
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts));
|
||||
|
||||
$theme = common_config('site', 'theme');
|
||||
|
||||
|
@ -278,7 +278,7 @@ class FacebookAction extends Action
|
|||
$this->element('a',
|
||||
array('href' => common_local_url('register')), _('Register'));
|
||||
$this->text($loginmsg_part2);
|
||||
$this->elementEnd('p');
|
||||
$this->elementEnd('p');
|
||||
$this->elementEnd('dd');
|
||||
|
||||
$this->elementEnd('dl');
|
||||
|
@ -317,7 +317,7 @@ class FacebookAction extends Action
|
|||
$this->elementEnd('ul');
|
||||
|
||||
$this->submit('submit', _('Login'));
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
|
||||
$this->elementStart('p');
|
||||
|
@ -336,65 +336,65 @@ class FacebookAction extends Action
|
|||
|
||||
// Need to include inline CSS for styling the Profile box
|
||||
|
||||
$app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url'));
|
||||
$icon_url = $app_props['icon_url'];
|
||||
$app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url'));
|
||||
$icon_url = $app_props['icon_url'];
|
||||
|
||||
$style = '<style>
|
||||
.entry-title *,
|
||||
.entry-content * {
|
||||
font-size:14px;
|
||||
font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||
}
|
||||
.entry-title a,
|
||||
.entry-content a {
|
||||
color:#002E6E;
|
||||
}
|
||||
.entry-title *,
|
||||
.entry-content * {
|
||||
font-size:14px;
|
||||
font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||
}
|
||||
.entry-title a,
|
||||
.entry-content a {
|
||||
color:#002E6E;
|
||||
}
|
||||
|
||||
.entry-title .vcard .photo {
|
||||
float:left;
|
||||
display:inline;
|
||||
margin-right:11px;
|
||||
margin-bottom:11px
|
||||
margin-right:11px;
|
||||
margin-bottom:11px
|
||||
}
|
||||
.entry-title {
|
||||
margin-bottom:11px;
|
||||
}
|
||||
.entry-title {
|
||||
margin-bottom:11px;
|
||||
}
|
||||
.entry-title p.entry-content {
|
||||
display:inline;
|
||||
margin-left:5px;
|
||||
margin-left:5px;
|
||||
}
|
||||
|
||||
div.entry-content {
|
||||
clear:both;
|
||||
}
|
||||
div.entry-content {
|
||||
clear:both;
|
||||
}
|
||||
div.entry-content dl,
|
||||
div.entry-content dt,
|
||||
div.entry-content dd {
|
||||
display:inline;
|
||||
text-transform:lowercase;
|
||||
text-transform:lowercase;
|
||||
}
|
||||
|
||||
div.entry-content dd,
|
||||
div.entry-content .device dt {
|
||||
margin-left:0;
|
||||
margin-right:5px;
|
||||
div.entry-content .device dt {
|
||||
margin-left:0;
|
||||
margin-right:5px;
|
||||
}
|
||||
div.entry-content dl.timestamp dt,
|
||||
div.entry-content dl.response dt {
|
||||
div.entry-content dl.response dt {
|
||||
display:none;
|
||||
}
|
||||
div.entry-content dd a {
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
#facebook_laconica_app {
|
||||
text-indent:-9999px;
|
||||
height:16px;
|
||||
width:16px;
|
||||
display:block;
|
||||
background:url('.$icon_url.') no-repeat 0 0;
|
||||
float:right;
|
||||
}
|
||||
#facebook_laconica_app {
|
||||
text-indent:-9999px;
|
||||
height:16px;
|
||||
width:16px;
|
||||
display:block;
|
||||
background:url('.$icon_url.') no-repeat 0 0;
|
||||
float:right;
|
||||
}
|
||||
</style>';
|
||||
|
||||
$this->xw->openMemory();
|
||||
|
@ -646,48 +646,16 @@ class FacebookNoticeListItem extends NoticeListItem
|
|||
function show()
|
||||
{
|
||||
$this->showStart();
|
||||
$this->showNotice();
|
||||
$this->showNoticeInfo();
|
||||
|
||||
$this->out->elementStart('div', 'entry-title');
|
||||
$this->showAuthor();
|
||||
$this->showContent();
|
||||
$this->out->elementEnd('div');
|
||||
|
||||
$this->out->elementStart('div', 'entry-content');
|
||||
$this->showNoticeLink();
|
||||
$this->showNoticeSource();
|
||||
$this->showReplyTo();
|
||||
$this->out->elementEnd('div');
|
||||
// XXX: Need to update to show attachements and controls
|
||||
|
||||
$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
|
||||
{
|
||||
|
||||
|
@ -706,28 +674,16 @@ class FacebookProfileBoxNotice extends FacebookNoticeListItem
|
|||
|
||||
/**
|
||||
* Recipe function for displaying a single notice in the
|
||||
* Facebook App's Profile
|
||||
* Facebook App profile notice box
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function show()
|
||||
{
|
||||
|
||||
$this->out->elementStart('div', 'entry-title');
|
||||
$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->showNotice();
|
||||
$this->showNoticeInfo();
|
||||
$this->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
|
||||
{
|
||||
var $enctype = null;
|
||||
|
||||
/**
|
||||
* Show the form
|
||||
*
|
||||
|
@ -63,11 +65,15 @@ class Form extends Widget
|
|||
|
||||
function show()
|
||||
{
|
||||
$this->out->elementStart('form',
|
||||
array('id' => $this->id(),
|
||||
'class' => $this->formClass(),
|
||||
'method' => 'post',
|
||||
'action' => $this->action()));
|
||||
$attributes = array('id' => $this->id(),
|
||||
'class' => $this->formClass(),
|
||||
'method' => 'post',
|
||||
'action' => $this->action());
|
||||
|
||||
if (!empty($this->enctype)) {
|
||||
$attributes['enctype'] = $this->enctype;
|
||||
}
|
||||
$this->out->elementStart('form', $attributes);
|
||||
$this->out->elementStart('fieldset');
|
||||
$this->formLegend();
|
||||
$this->sessionToken();
|
||||
|
|
|
@ -335,6 +335,7 @@ function mail_broadcast_notice_sms($notice)
|
|||
"FROM $UT JOIN subscription " .
|
||||
"ON $UT.id = subscription.subscriber " .
|
||||
'WHERE subscription.subscribed = ' . $notice->profile_id . ' ' .
|
||||
'AND subscription.subscribed != subscription.subscriber ' .
|
||||
"AND $UT.smsemail IS NOT null " .
|
||||
"AND $UT.smsnotify = 1 " .
|
||||
'AND subscription.sms = 1 ');
|
||||
|
|
|
@ -90,6 +90,7 @@ class NoticeForm extends Form
|
|||
$this->user = common_current_user();
|
||||
}
|
||||
|
||||
$this->enctype = 'multipart/form-data';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -142,17 +143,21 @@ class NoticeForm extends Form
|
|||
'rows' => 4,
|
||||
'name' => 'status_textarea'),
|
||||
($this->content) ? $this->content : '');
|
||||
|
||||
$this->out->elementStart('dl', 'form_note');
|
||||
$this->out->element('dt', null, _('Available characters'));
|
||||
$this->out->element('dd', array('id' => 'notice_text-count'),
|
||||
'140');
|
||||
$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) {
|
||||
$this->out->hidden('notice_return-to', $this->action, 'returnto');
|
||||
}
|
||||
$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->element('h2', null, _('Notices'));
|
||||
$this->out->elementStart('ul', array('class' => 'notices'));
|
||||
$this->out->elementStart('ol', array('class' => 'notices xoxo'));
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
|
@ -100,7 +100,7 @@ class NoticeList extends Widget
|
|||
$item->show();
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('ol');
|
||||
$this->out->elementEnd('div');
|
||||
|
||||
return $cnt;
|
||||
|
@ -205,6 +205,7 @@ class NoticeListItem extends Widget
|
|||
return 'shownotice' !== $this->out->args['action'];
|
||||
}
|
||||
|
||||
/*
|
||||
function attachmentCount($discriminant = true) {
|
||||
$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;
|
||||
|
@ -212,11 +213,16 @@ class NoticeListItem extends Widget
|
|||
$file_oembed->fetch();
|
||||
return intval($file_oembed->c);
|
||||
}
|
||||
*/
|
||||
|
||||
function showWithAttachment() {
|
||||
}
|
||||
|
||||
function showNoticeInfo()
|
||||
{
|
||||
$this->out->elementStart('div', 'entry-content');
|
||||
$this->showNoticeLink();
|
||||
// $this->showWithAttachment();
|
||||
$this->showNoticeSource();
|
||||
$this->showContext();
|
||||
$this->out->elementEnd('div');
|
||||
|
@ -357,6 +363,10 @@ class NoticeListItem extends Widget
|
|||
// versions (>> 0.4.x)
|
||||
$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');
|
||||
}
|
||||
|
||||
|
@ -387,6 +397,7 @@ class NoticeListItem extends Widget
|
|||
$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');
|
||||
|
|
|
@ -52,12 +52,12 @@ class NoticeSection extends Section
|
|||
{
|
||||
$notices = $this->getNotices();
|
||||
$cnt = 0;
|
||||
$this->out->elementStart('ul', 'notices');
|
||||
$this->out->elementStart('ol', 'notices xoxo');
|
||||
while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) {
|
||||
$this->showNotice($notices);
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('ol');
|
||||
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)
|
||||
{
|
||||
|
||||
common_debug('Posting notice ' . $notice->id . ' to ' . $postnoticeurl, __FILE__);
|
||||
|
||||
$user = User::staticGet('id', $notice->profile_id);
|
||||
|
||||
if (!$user) {
|
||||
common_debug('Failed to get user for notice ' . $notice->id . ', profile = ' . $notice->profile_id, __FILE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -208,8 +204,6 @@ function omb_post_notice_keys($notice, $postnoticeurl, $tk, $secret)
|
|||
$req->to_postdata(),
|
||||
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
|
||||
common_debug('403 result, deleting subscription', __FILE__);
|
||||
# FIXME: figure out how to delete this
|
||||
|
@ -286,14 +280,10 @@ function omb_update_profile($profile, $remote_profile, $subscription)
|
|||
|
||||
$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(),
|
||||
$req->to_postdata(),
|
||||
array('User-Agent: Laconica/' . LACONICA_VERSION));
|
||||
|
||||
common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__);
|
||||
|
||||
if (empty($result) || !$result) {
|
||||
common_debug("Unable to contact " . $req->get_normalized_http_url());
|
||||
} else if ($result->status == 403) { # not authorized, don't send again
|
||||
|
|
|
@ -164,6 +164,10 @@ class Router
|
|||
array('action' => 'newnotice'),
|
||||
array('replyto' => '[A-Za-z0-9_-]+'));
|
||||
|
||||
$m->connect('notice/:notice/file',
|
||||
array('action' => 'file'),
|
||||
array('notice' => '[0-9]+'));
|
||||
|
||||
$m->connect('notice/:notice',
|
||||
array('action' => 'shownotice'),
|
||||
array('notice' => '[0-9]+'));
|
||||
|
|
|
@ -73,21 +73,82 @@ class TwitterapiAction extends Action
|
|||
|
||||
function twitter_user_array($profile, $get_notice=false)
|
||||
{
|
||||
|
||||
$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['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);
|
||||
$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['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) {
|
||||
$notice = $profile->getCurrentNotice();
|
||||
|
@ -612,7 +673,27 @@ class TwitterapiAction extends Action
|
|||
function get_user($id, $apidata=null)
|
||||
{
|
||||
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)) {
|
||||
return User::staticGet($id);
|
||||
} 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'
|
||||
// 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'";
|
||||
$file = new File;
|
||||
$file->query($query);
|
||||
|
@ -895,6 +900,34 @@ function common_enqueue_notice($notice)
|
|||
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)
|
||||
{
|
||||
$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);
|
||||
|
||||
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') {
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
|
@ -78,7 +99,7 @@ class FBConnectauthAction extends Action
|
|||
}
|
||||
$this->createNewUser();
|
||||
} else if ($this->arg('connect')) {
|
||||
$this->connectUser();
|
||||
$this->connectNewUser();
|
||||
} else {
|
||||
common_debug(print_r($this->args, true), __FILE__);
|
||||
$this->showForm(_('Something weird happened.'),
|
||||
|
@ -259,7 +280,7 @@ class FBConnectauthAction extends Action
|
|||
303);
|
||||
}
|
||||
|
||||
function connectUser()
|
||||
function connectNewUser()
|
||||
{
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$password = $this->trimmed('password');
|
||||
|
@ -290,6 +311,23 @@ class FBConnectauthAction extends Action
|
|||
$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()
|
||||
{
|
||||
common_debug("Trying Facebook Login...");
|
||||
|
|
|
@ -58,8 +58,6 @@ class FBConnectLoginAction extends Action
|
|||
function showContent() {
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
|
||||
|
||||
$this->element('fb:login-button', array('onlogin' => 'goto_login()',
|
||||
'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/FBCLoginGroupNav.php';
|
||||
require_once INSTALLDIR . '/plugins/FBConnect/FBCSettingsNav.php';
|
||||
require_once INSTALLDIR . '/plugins/FBConnect/FBC_XDReceiver.php';
|
||||
|
||||
/**
|
||||
* Plugin to enable Facebook Connect
|
||||
|
@ -62,27 +63,19 @@ class FBConnectPlugin extends Plugin
|
|||
$m->connect('main/facebookconnect', array('action' => 'FBConnectAuth'));
|
||||
$m->connect('main/facebooklogin', array('action' => 'FBConnectLogin'));
|
||||
$m->connect('settings/facebook', array('action' => 'FBConnectSettings'));
|
||||
$m->connect('xd_receiver.html', array('action' => 'FBC_XDReceiver'));
|
||||
}
|
||||
|
||||
// Add in xmlns:fb
|
||||
function onStartShowHTML($action)
|
||||
{
|
||||
$httpaccept = isset($_SERVER['HTTP_ACCEPT']) ?
|
||||
$_SERVER['HTTP_ACCEPT'] : null;
|
||||
|
||||
// XXX: allow content negotiation for RDF, RSS, or XRDS
|
||||
|
||||
$cp = common_accept_to_prefs($httpaccept);
|
||||
$sp = common_accept_to_prefs(PAGE_TYPE_PREFS);
|
||||
|
||||
$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);
|
||||
// XXX: Horrible hack to make Safari, FF2, and Chrome work with
|
||||
// Facebook Connect. These browser cannot use Facebook's
|
||||
// DOM parsing routines unless the mime type of the page is
|
||||
// text/html even though Facebook Connect uses XHTML. This is
|
||||
// A bug in Facebook Connect, and this is a temporary solution
|
||||
// until they fix their JavaScript libs.
|
||||
header('Content-Type: text/html');
|
||||
|
||||
$action->extraHeaders();
|
||||
|
||||
|
@ -101,20 +94,27 @@ class FBConnectPlugin extends Plugin
|
|||
return false;
|
||||
}
|
||||
|
||||
function onEndShowLaconicaScripts($action)
|
||||
{
|
||||
$action->element('script',
|
||||
array('type' => 'text/javascript',
|
||||
'src' => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php'),
|
||||
' ');
|
||||
// Note: this script needs to appear in the <body>
|
||||
|
||||
function onStartShowHeader($action)
|
||||
{
|
||||
$apikey = common_config('facebook', 'apikey');
|
||||
$plugin_path = common_path('plugins/FBConnect');
|
||||
|
||||
$login_url = common_local_url('FBConnectAuth');
|
||||
$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() {
|
||||
window.location = "%s";
|
||||
|
@ -123,13 +123,23 @@ class FBConnectPlugin extends Plugin
|
|||
function goto_logout() {
|
||||
window.location = "%s";
|
||||
}
|
||||
|
||||
</script>', $apikey, $plugin_path, $login_url, $logout_url);
|
||||
|
||||
</script>', $apikey,
|
||||
$login_url, $logout_url);
|
||||
|
||||
$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)
|
||||
{
|
||||
$action->element('link', array('rel' => 'stylesheet',
|
||||
|
@ -143,24 +153,8 @@ class FBConnectPlugin extends Plugin
|
|||
|
||||
if ($user) {
|
||||
|
||||
$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');
|
||||
|
||||
$flink = Foreign_link::getByUserId($user->id, FACEBOOK_CONNECT_SERVICE);
|
||||
$flink = Foreign_link::getByUserId($user->id,
|
||||
FACEBOOK_CONNECT_SERVICE);
|
||||
$fbuid = 0;
|
||||
|
||||
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');
|
||||
$title = _('Logout from the site');
|
||||
|
@ -258,21 +268,32 @@ class FBConnectPlugin extends Plugin
|
|||
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();
|
||||
$fbuid = $facebook->get_loggedin_user();
|
||||
|
||||
if ($fbuid > 0) {
|
||||
$facebook->logout(common_local_url('public'));
|
||||
try {
|
||||
$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()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$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',
|
||||
'id' => 'form_settings_facebook',
|
||||
'class' => 'form_settings',
|
||||
'action' =>
|
||||
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 {
|
||||
$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');
|
||||
}
|
||||
|
||||
|
@ -171,8 +181,7 @@ class FBConnectSettingsAction extends ConnectSettingsAction
|
|||
|
||||
try {
|
||||
|
||||
// XXX: not sure what exactly to do here
|
||||
|
||||
// Clear FB Connect cookies out
|
||||
$facebook = getFacebook();
|
||||
$facebook->clear_cookie_state();
|
||||
|
||||
|
@ -182,7 +191,7 @@ class FBConnectSettingsAction extends ConnectSettingsAction
|
|||
$e->getMessage());
|
||||
}
|
||||
|
||||
$this->showForm(_('Facebook user disconnected.'), true);
|
||||
$this->showForm(_('You have disconnected from Facebook.'), true);
|
||||
|
||||
} else {
|
||||
$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.
|
||||
*/
|
||||
|
||||
|
||||
# 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";
|
||||
|
@ -51,5 +50,4 @@ echo "ombqueuehandler.php ";
|
|||
echo "twitterqueuehandler.php ";
|
||||
echo "facebookqueuehandler.php ";
|
||||
echo "pingqueuehandler.php ";
|
||||
echo "inboxqueuehandler.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`
|
||||
|
||||
for f in jabberhandler ombhandler publichandler smshandler pinghandler \
|
||||
xmppconfirmhandler xmppdaemon twitterhandler facebookhandler \
|
||||
memcachehandler inboxhandler twitterstatusfetcher; do
|
||||
xmppconfirmhandler xmppdaemon twitterhandler facebookhandler; do
|
||||
|
||||
FILES="$DIR/$f.*.pid"
|
||||
for ff in "$FILES" ; do
|
||||
|
|
|
@ -452,6 +452,21 @@ 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 {
|
||||
display:none;
|
||||
}
|
||||
|
@ -855,20 +870,6 @@ display:inline-block;
|
|||
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 {
|
||||
position:relative;
|
||||
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 {
|
||||
float: left;
|
||||
margin-right: 2em;
|
||||
|
@ -1182,6 +1252,7 @@ width:33%;
|
|||
}
|
||||
#settings_design_color .form_data label {
|
||||
float:none;
|
||||
display:block;
|
||||
}
|
||||
#settings_design_color .form_data .swatch {
|
||||
padding:11px;
|
||||
|
|
|
@ -30,3 +30,12 @@ margin-right:4px;
|
|||
.entity_profile {
|
||||
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;
|
||||
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 {
|
||||
display:none;
|
||||
}
|
||||
|
|
|
@ -102,6 +102,13 @@ color:#333;
|
|||
#form_notice.warning #notice_text-count {
|
||||
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 {
|
||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||
cursor:wait;
|
||||
|
|
|
@ -82,6 +82,13 @@ color:#333;
|
|||
#form_notice.warning #notice_text-count {
|
||||
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 {
|
||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||
cursor:wait;
|
||||
|
@ -175,6 +182,12 @@ background-image:url(../../base/images/icons/twotone/green/shield.gif);
|
|||
}
|
||||
|
||||
/* 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 form input.submit {
|
||||
background-color:transparent;
|
||||
|
|
|
@ -82,6 +82,13 @@ color:#333;
|
|||
#form_notice.warning #notice_text-count {
|
||||
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 {
|
||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||
cursor:wait;
|
||||
|
@ -175,6 +182,12 @@ background-image:url(../../base/images/icons/twotone/green/shield.gif);
|
|||
}
|
||||
|
||||
/* 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 form input.submit {
|
||||
background-color:transparent;
|
||||
|
|
Loading…
Reference in New Issue
Block a user