summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README13
-rw-r--r--actions/api.php1
-rw-r--r--actions/attachment.php22
-rw-r--r--actions/finishopenidlogin.php2
-rw-r--r--actions/recoverpassword.php3
-rw-r--r--actions/shownotice.php14
-rw-r--r--actions/twitapilaconica.php1
-rw-r--r--actions/twitapioembed.php173
-rw-r--r--classes/Fave.php2
-rw-r--r--classes/File.php9
-rw-r--r--classes/File_oembed.php55
-rw-r--r--classes/File_thumbnail.php6
-rw-r--r--classes/Notice.php24
-rw-r--r--classes/Profile.php4
-rw-r--r--classes/Session.php9
-rw-r--r--classes/User_group.php7
-rw-r--r--db/laconica_pg.sql65
-rw-r--r--db/sms_carrier.sql3
-rw-r--r--extlib/Services/oEmbed.php4
-rw-r--r--htaccess.sample14
-rw-r--r--index.php3
-rw-r--r--install.php218
-rw-r--r--lib/common.php2
-rw-r--r--lib/daemon.php11
-rw-r--r--lib/dbqueuemanager.php7
-rw-r--r--lib/groupsbymemberssection.php2
-rw-r--r--lib/groupsbypostssection.php2
-rw-r--r--lib/grouptagcloudsection.php2
-rw-r--r--lib/language.php2
-rw-r--r--lib/mail.php2
-rw-r--r--lib/popularnoticesection.php6
-rw-r--r--lib/queuehandler.php11
-rw-r--r--lib/router.php11
-rw-r--r--lib/rssaction.php87
-rw-r--r--lib/twitterapi.php85
-rw-r--r--lib/util.php6
-rwxr-xr-xscripts/getvaliddaemons.php3
-rwxr-xr-xscripts/maildaemon.php43
-rwxr-xr-xscripts/twitterstatusfetcher.php31
-rwxr-xr-xscripts/xmppdaemon.php5
-rw-r--r--theme/base/css/ie6.css2
-rw-r--r--theme/cloudy/css/display.css222
-rw-r--r--theme/cloudy/css/ie.css20
-rw-r--r--theme/pigeonthoughts/css/base.css44
-rw-r--r--theme/pigeonthoughts/css/display.css3
45 files changed, 974 insertions, 287 deletions
diff --git a/README b/README
index 0214e4931..0bf1319c6 100644
--- a/README
+++ b/README
@@ -134,7 +134,7 @@ Prerequisites
The following software packages are *required* for this software to
run correctly.
-- PHP 5.2.x. It may be possible to run this software on earlier
+- PHP 5.2.3+. It may be possible to run this software on earlier
versions of PHP, but many of the functions used are only available
in PHP 5.2 or above.
- MySQL 5.x. The Laconica database is stored, by default, in a MySQL
@@ -262,13 +262,16 @@ especially if you've previously installed PHP/MySQL packages.
that user's default group instead. As a last resort, you can create
a new group like "mublog" and add the Web server's user to the group.
-4. You should also take this moment to make your avatar subdirectory
- writeable by the Web server. An insecure way to do this is:
+4. You should also take this moment to make your avatar, background, and
+ file subdirectories writeable by the Web server. An insecure way to do
+ this is:
chmod a+w /var/www/mublog/avatar
+ chmod a+w /var/www/mublog/background
+ chmod a+w /var/www/mublog/file
- You can also make the avatar directory writeable by the Web server
- group, as noted above.
+ You can also make the avatar, background, and file directories
+ writeable by the Web server group, as noted above.
5. Create a database to hold your microblog data. Something like this
should work:
diff --git a/actions/api.php b/actions/api.php
index 452ed8e82..8b92889f8 100644
--- a/actions/api.php
+++ b/actions/api.php
@@ -129,6 +129,7 @@ class ApiAction extends Action
'laconica/config',
'laconica/wadl',
'tags/timeline',
+ 'oembed/oembed',
'groups/timeline');
static $bareauth = array('statuses/user_timeline',
diff --git a/actions/attachment.php b/actions/attachment.php
index ee4cd9640..c6a5d0d52 100644
--- a/actions/attachment.php
+++ b/actions/attachment.php
@@ -98,6 +98,28 @@ class AttachmentAction extends Action
return $a->title();
}
+ function extraHead()
+ {
+ $this->element('link',array('rel'=>'alternate',
+ 'type'=>'application/json+oembed',
+ 'href'=>common_local_url(
+ 'api',
+ array('apiaction'=>'oembed','method'=>'oembed.json'),
+ array('url'=>
+ common_local_url('attachment',
+ array('attachment' => $this->attachment->id)))),
+ 'title'=>'oEmbed'),null);
+ $this->element('link',array('rel'=>'alternate',
+ 'type'=>'text/xml+oembed',
+ 'href'=>common_local_url(
+ 'api',
+ array('apiaction'=>'oembed','method'=>'oembed.xml'),
+ array('url'=>
+ common_local_url('attachment',
+ array('attachment' => $this->attachment->id)))),
+ 'title'=>'oEmbed'),null);
+ }
+
/**
* Handle input
*
diff --git a/actions/finishopenidlogin.php b/actions/finishopenidlogin.php
index e9f7c746b..ff0b35218 100644
--- a/actions/finishopenidlogin.php
+++ b/actions/finishopenidlogin.php
@@ -83,7 +83,7 @@ class FinishopenidloginAction extends Action
function showContent()
{
if (!empty($this->message_text)) {
- $this->element('p', null, $this->message);
+ $this->element('div', array('class' => 'error'), $this->message_text);
return;
}
diff --git a/actions/recoverpassword.php b/actions/recoverpassword.php
index 2afd052a7..721edea7f 100644
--- a/actions/recoverpassword.php
+++ b/actions/recoverpassword.php
@@ -194,6 +194,9 @@ class RecoverpasswordAction extends Action
'or your registered email address.'));
$this->elementEnd('li');
$this->elementEnd('ul');
+ $this->element('input', array('name' => 'recover',
+ 'type' => 'hidden',
+ 'value' => _('Recover')));
$this->submit('recover', _('Recover'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
diff --git a/actions/shownotice.php b/actions/shownotice.php
index 1ec38a76b..8f73dc824 100644
--- a/actions/shownotice.php
+++ b/actions/shownotice.php
@@ -275,6 +275,20 @@ class ShownoticeAction extends OwnerDesignAction
$this->element('meta', array('name' => 'microid',
'content' => $id->toString()));
}
+ $this->element('link',array('rel'=>'alternate',
+ 'type'=>'application/json+oembed',
+ 'href'=>common_local_url(
+ 'api',
+ array('apiaction'=>'oembed','method'=>'oembed.json'),
+ array('url'=>$this->notice->uri)),
+ 'title'=>'oEmbed'),null);
+ $this->element('link',array('rel'=>'alternate',
+ 'type'=>'text/xml+oembed',
+ 'href'=>common_local_url(
+ 'api',
+ array('apiaction'=>'oembed','method'=>'oembed.xml'),
+ array('url'=>$this->notice->uri)),
+ 'title'=>'oEmbed'),null);
}
}
diff --git a/actions/twitapilaconica.php b/actions/twitapilaconica.php
index 8cd7a64b9..442fdbcef 100644
--- a/actions/twitapilaconica.php
+++ b/actions/twitapilaconica.php
@@ -171,4 +171,5 @@ class TwitapilaconicaAction extends TwitterapiAction
parent::handle($args);
$this->serverError(_('API method under construction.'), 501);
}
+
}
diff --git a/actions/twitapioembed.php b/actions/twitapioembed.php
new file mode 100644
index 000000000..3019e5878
--- /dev/null
+++ b/actions/twitapioembed.php
@@ -0,0 +1,173 @@
+<?php
+/**
+ * Laconica, the distributed open-source microblogging tool
+ *
+ * Laconica-only extensions to the Twitter-like API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Twitter
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @copyright 2008 Control Yourself, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://laconi.ca/
+ */
+
+if (!defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/twitterapi.php';
+
+/**
+ * Oembed provider implementation
+ *
+ * This class handles all /main/oembed(.xml|.json)/ requests.
+ *
+ * @category oEmbed
+ * @package Laconica
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2008 Control Yourself, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://laconi.ca/
+ */
+
+class TwitapioembedAction extends TwitterapiAction
+{
+
+ function oembed($args, $apidata)
+ {
+ parent::handle($args);
+
+ common_debug("in oembed api action");
+
+ $this->auth_user = $apidata['user'];
+
+ $url = $args['url'];
+ if( substr(strtolower($url),0,strlen(common_root_url())) == strtolower(common_root_url()) ){
+ $path = substr($url,strlen(common_root_url()));
+
+ $r = Router::get();
+
+ $proxy_args = $r->map($path);
+
+ if (!$proxy_args) {
+ $this->serverError(_("$path not found"), 404);
+ }
+ $oembed=array();
+ $oembed['version']='1.0';
+ $oembed['provider_name']=common_config('site', 'name');
+ $oembed['provider_url']=common_root_url();
+ switch($proxy_args['action']){
+ case 'shownotice':
+ $oembed['type']='link';
+ $id = $proxy_args['notice'];
+ $notice = Notice::staticGet($id);
+ if(empty($notice)){
+ $this->serverError(_("notice $id not found"), 404);
+ }
+ $profile = $notice->getProfile();
+ if (empty($profile)) {
+ $this->serverError(_('Notice has no profile'), 500);
+ }
+ if (!empty($profile->fullname)) {
+ $authorname = $profile->fullname . ' (' . $profile->nickname . ')';
+ } else {
+ $authorname = $profile->nickname;
+ }
+ $oembed['title'] = sprintf(_('%1$s\'s status on %2$s'),
+ $authorname,
+ common_exact_date($notice->created));
+ $oembed['author_name']=$authorname;
+ $oembed['author_url']=$profile->profileurl;
+ $oembed['url']=($notice->url?$notice->url:$notice->uri);
+ $oembed['html']=$notice->rendered;
+ break;
+ case 'attachment':
+ $id = $proxy_args['attachment'];
+ $attachment = File::staticGet($id);
+ if(empty($attachment)){
+ $this->serverError(_("attachment $id not found"), 404);
+ }
+ if(empty($attachment->filename) && $file_oembed = File_oembed::staticGet('file_id', $attachment->id)){
+ // Proxy the existing oembed information
+ $oembed['type']=$file_oembed->type;
+ $oembed['provider']=$file_oembed->provider;
+ $oembed['provider_url']=$file_oembed->provider_url;
+ $oembed['width']=$file_oembed->width;
+ $oembed['height']=$file_oembed->height;
+ $oembed['html']=$file_oembed->html;
+ $oembed['title']=$file_oembed->title;
+ $oembed['author_name']=$file_oembed->author_name;
+ $oembed['author_url']=$file_oembed->author_url;
+ $oembed['url']=$file_oembed->url;
+ }else if(substr($attachment->mimetype,0,strlen('image/'))=='image/'){
+ $oembed['type']='photo';
+ //TODO set width and height
+ //$oembed['width']=
+ //$oembed['height']=
+ $oembed['url']=$attachment->url;
+ }else{
+ $oembed['type']='link';
+ $oembed['url']=common_local_url('attachment',
+ array('attachment' => $attachment->id));
+ }
+ if($attachment->title) $oembed['title']=$attachment->title;
+ break;
+ default:
+ $this->serverError(_("$path not supported for oembed requests"), 501);
+ }
+
+ switch($apidata['content-type']){
+ case 'xml':
+ $this->init_document('xml');
+ $this->elementStart('oembed');
+ $this->element('version',null,$oembed['version']);
+ $this->element('type',null,$oembed['type']);
+ if($oembed['provider_name']) $this->element('provider_name',null,$oembed['provider_name']);
+ if($oembed['provider_url']) $this->element('provider_url',null,$oembed['provider_url']);
+ if($oembed['title']) $this->element('title',null,$oembed['title']);
+ if($oembed['author_name']) $this->element('author_name',null,$oembed['author_name']);
+ if($oembed['author_url']) $this->element('author_url',null,$oembed['author_url']);
+ if($oembed['url']) $this->element('url',null,$oembed['url']);
+ if($oembed['html']) $this->element('html',null,$oembed['html']);
+ if($oembed['width']) $this->element('width',null,$oembed['width']);
+ if($oembed['height']) $this->element('height',null,$oembed['height']);
+ if($oembed['cache_age']) $this->element('cache_age',null,$oembed['cache_age']);
+ if($oembed['thumbnail_url']) $this->element('thumbnail_url',null,$oembed['thumbnail_url']);
+ if($oembed['thumbnail_width']) $this->element('thumbnail_width',null,$oembed['thumbnail_width']);
+ if($oembed['thumbnail_height']) $this->element('thumbnail_height',null,$oembed['thumbnail_height']);
+
+
+ $this->elementEnd('oembed');
+ $this->end_document('xml');
+ break;
+ case 'json':
+ $this->init_document('json');
+ print(json_encode($oembed));
+ $this->end_document('json');
+ break;
+ default:
+ $this->serverError(_('content type ' . $apidata['content-type'] . ' not supported'), 501);
+ }
+
+ }else{
+ $this->serverError(_('Only ' . common_root_url() . ' urls over plain http please'), 404);
+ }
+ }
+}
+
diff --git a/classes/Fave.php b/classes/Fave.php
index c3ec62dcf..4b28d06b4 100644
--- a/classes/Fave.php
+++ b/classes/Fave.php
@@ -79,7 +79,7 @@ class Fave extends Memcached_DataObject
$qry .= 'ORDER BY modified DESC ';
if (!is_null($offset)) {
- $qry .= "LIMIT $offset, $limit";
+ $qry .= "LIMIT $limit OFFSET $offset";
}
$fav->query($qry);
diff --git a/classes/File.php b/classes/File.php
index 56d9f9827..0c4fbf7e6 100644
--- a/classes/File.php
+++ b/classes/File.php
@@ -79,9 +79,8 @@ class File extends Memcached_DataObject
if (isset($redir_data['type'])
&& ('text/html' === substr($redir_data['type'], 0, 9))
- && ($oembed_data = File_oembed::_getOembed($given_url))
- && isset($oembed_data['json'])) {
- File_oembed::saveNew($oembed_data['json'], $file_id);
+ && ($oembed_data = File_oembed::_getOembed($given_url))) {
+ File_oembed::saveNew($oembed_data, $file_id);
}
return $x;
}
@@ -123,6 +122,7 @@ class File extends Memcached_DataObject
}
function isRespectsQuota($user,$fileSize) {
+
if ($fileSize > 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.'),
@@ -136,8 +136,7 @@ class File extends Memcached_DataObject
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())';
+ $query .= ' AND EXTRACT(month FROM file.modified) = EXTRACT(month FROM now()) and EXTRACT(year FROM file.modified) = EXTRACT(year FROM now())';
$this->query($query);
$this->fetch();
$total = $this->total + $fileSize;
diff --git a/classes/File_oembed.php b/classes/File_oembed.php
index 69230e4a4..bbf112729 100644
--- a/classes/File_oembed.php
+++ b/classes/File_oembed.php
@@ -56,33 +56,46 @@ class File_oembed extends Memcached_DataObject
return array(false, false, false);
}
- function _getOembed($url, $maxwidth = 500, $maxheight = 400, $format = 'json') {
- $cmd = common_config('oohembed', 'endpoint') . '?url=' . urlencode($url);
- if (is_int($maxwidth)) $cmd .= "&maxwidth=$maxwidth";
- if (is_int($maxheight)) $cmd .= "&maxheight=$maxheight";
- if (is_string($format)) $cmd .= "&format=$format";
- $oe = @file_get_contents($cmd);
- if (false === $oe) return false;
- return array($format => (('json' === $format) ? json_decode($oe, true) : $oe));
+ function _getOembed($url, $maxwidth = 500, $maxheight = 400) {
+ require_once INSTALLDIR.'/extlib/Services/oEmbed.php';
+ $parameters = array(
+ 'maxwidth'=>$maxwidth,
+ 'maxheight'=>$maxheight,
+ );
+ try{
+ $oEmbed = new Services_oEmbed($url);
+ $object = $oEmbed->getObject($parameters);
+ return $object;
+ }catch(Exception $e){
+ try{
+ $oEmbed = new Services_oEmbed($url, array(
+ Services_oEmbed::OPTION_API => common_config('oohembed', 'endpoint')
+ ));
+ $object = $oEmbed->getObject($parameters);
+ return $object;
+ }catch(Exception $ex){
+ return false;
+ }
+ }
}
function saveNew($data, $file_id) {
$file_oembed = new File_oembed;
$file_oembed->file_id = $file_id;
- $file_oembed->version = $data['version'];
- $file_oembed->type = $data['type'];
- if (!empty($data['provider_name'])) $file_oembed->provider = $data['provider_name'];
- if (!isset($file_oembed->provider) && !empty($data['provide'])) $file_oembed->provider = $data['provider'];
- if (!empty($data['provide_url'])) $file_oembed->provider_url = $data['provider_url'];
- if (!empty($data['width'])) $file_oembed->width = intval($data['width']);
- if (!empty($data['height'])) $file_oembed->height = intval($data['height']);
- if (!empty($data['html'])) $file_oembed->html = $data['html'];
- if (!empty($data['title'])) $file_oembed->title = $data['title'];
- if (!empty($data['author_name'])) $file_oembed->author_name = $data['author_name'];
- if (!empty($data['author_url'])) $file_oembed->author_url = $data['author_url'];
- if (!empty($data['url'])) $file_oembed->url = $data['url'];
+ $file_oembed->version = $data->version;
+ $file_oembed->type = $data->type;
+ if (!empty($data->provider_name)) $file_oembed->provider = $data->provider_name;
+ if (!empty($data->provider)) $file_oembed->provider = $data->provider;
+ if (!empty($data->provide_url)) $file_oembed->provider_url = $data->provider_url;
+ if (!empty($data->width)) $file_oembed->width = intval($data->width);
+ if (!empty($data->height)) $file_oembed->height = intval($data->height);
+ if (!empty($data->html)) $file_oembed->html = $data->html;
+ if (!empty($data->title)) $file_oembed->title = $data->title;
+ if (!empty($data->author_name)) $file_oembed->author_name = $data->author_name;
+ if (!empty($data->author_url)) $file_oembed->author_url = $data->author_url;
+ if (!empty($data->url)) $file_oembed->url = $data->url;
$file_oembed->insert();
- if (!empty($data['thumbnail_url'])) {
+ if (!empty($data->thumbnail_url)) {
File_thumbnail::saveNew($data, $file_id);
}
}
diff --git a/classes/File_thumbnail.php b/classes/File_thumbnail.php
index 44b92a2fa..0b09c6af8 100644
--- a/classes/File_thumbnail.php
+++ b/classes/File_thumbnail.php
@@ -51,9 +51,9 @@ class File_thumbnail extends Memcached_DataObject
function saveNew($data, $file_id) {
$tn = new File_thumbnail;
$tn->file_id = $file_id;
- $tn->url = $data['thumbnail_url'];
- $tn->width = intval($data['thumbnail_width']);
- $tn->height = intval($data['thumbnail_height']);
+ $tn->url = $data->thumbnail_url;
+ $tn->width = intval($data->thumbnail_width);
+ $tn->height = intval($data->thumbnail_height);
$tn->insert();
}
}
diff --git a/classes/Notice.php b/classes/Notice.php
index 0359c310d..7f002d838 100644
--- a/classes/Notice.php
+++ b/classes/Notice.php
@@ -97,13 +97,21 @@ class Notice extends Memcached_DataObject
function saveTags()
{
/* extract all #hastags */
- $count = preg_match_all('/(?:^|\s)#([A-Za-z0-9_\-\.]{1,64})/', strtolower($this->content), $match);
+ $count = preg_match_all('/(?:^|\s)#([\pL\pN_\-\.]{1,64})/', strtolower($this->content), $match);
if (!$count) {
return true;
}
+
+ //turn each into their canonical tag
+ //this is needed to remove dupes before saving e.g. #hash.tag = #hashtag
+ $hashtags = array();
+ for($i=0; $i<count($match[1]); $i++) {
+ $hashtags[] = common_canonical_tag($match[1][$i]);
+ }
+
/* Add them to the database */
- foreach(array_unique($match[1]) as $hashtag) {
+ foreach(array_unique($hashtags) as $hashtag) {
/* elide characters we don't want in the tag */
$this->saveTag($hashtag);
}
@@ -112,8 +120,6 @@ class Notice extends Memcached_DataObject
function saveTag($hashtag)
{
- $hashtag = common_canonical_tag($hashtag);
-
$tag = new Notice_tag();
$tag->notice_id = $this->id;
$tag->tag = $hashtag;
@@ -873,7 +879,7 @@ class Notice extends Memcached_DataObject
if ($cnt > 0) {
$qry .= ', ';
}
- $qry .= '('.$id.', '.$this->id.', '.$source.', "'.$this->created.'") ';
+ $qry .= '('.$id.', '.$this->id.', '.$source.", '".$this->created. "') ";
$cnt++;
if (rand() % NOTICE_INBOX_SOFT_LIMIT == 0) {
Notice_inbox::gc($id);
@@ -899,10 +905,14 @@ class Notice extends Memcached_DataObject
{
$user = new User();
+ if(common_config('db','quote_identifiers'))
+ $user_table = '"user"';
+ else $user_table = 'user';
+
$qry =
'SELECT id ' .
- 'FROM user JOIN subscription '.
- 'ON user.id = subscription.subscriber ' .
+ 'FROM '. $user_table .' JOIN subscription '.
+ 'ON '. $user_table .'.id = subscription.subscriber ' .
'WHERE subscription.subscribed = %d ';
$user->query(sprintf($qry, $this->profile_id));
diff --git a/classes/Profile.php b/classes/Profile.php
index 32de608cf..f926b2cef 100644
--- a/classes/Profile.php
+++ b/classes/Profile.php
@@ -360,7 +360,6 @@ class Profile extends Memcached_DataObject
$c->set(common_cache_key('profile:subscription_count:'.$this->id), $cnt);
}
- common_debug("subscriptionCount == $cnt");
return $cnt;
}
@@ -385,7 +384,6 @@ class Profile extends Memcached_DataObject
$c->set(common_cache_key('profile:subscriber_count:'.$this->id), $cnt);
}
- common_debug("subscriberCount == $cnt");
return $cnt;
}
@@ -407,7 +405,6 @@ class Profile extends Memcached_DataObject
$c->set(common_cache_key('profile:fave_count:'.$this->id), $cnt);
}
- common_debug("faveCount == $cnt");
return $cnt;
}
@@ -430,7 +427,6 @@ class Profile extends Memcached_DataObject
$c->set(common_cache_key('profile:notice_count:'.$this->id), $cnt);
}
- common_debug("noticeCount == $cnt");
return $cnt;
}
diff --git a/classes/Session.php b/classes/Session.php
index 93fd99baa..ac80279c5 100644
--- a/classes/Session.php
+++ b/classes/Session.php
@@ -106,14 +106,11 @@ class Session extends Memcached_DataObject
{
self::logdeb("garbage collection (maxlifetime = $maxlifetime)");
- $epoch = time() - $maxlifetime;
-
- $qry = 'DELETE FROM session ' .
- 'WHERE modified < "'.$epoch.'"';
+ $epoch = common_sql_date(time() - $maxlifetime);
$session = new Session();
-
- $result = $session->query($qry);
+ $session->whereAdd('modified < "'.$epoch.'"');
+ $result = $session->delete(DB_DATAOBJECT_WHEREADD_ONLY);
self::logdeb("garbage collection result = $result");
}
diff --git a/classes/User_group.php b/classes/User_group.php
index 27b444705..b1ab1c2d3 100644
--- a/classes/User_group.php
+++ b/classes/User_group.php
@@ -275,11 +275,14 @@ class User_group extends Memcached_DataObject
// XXX: cache this
$user = new User();
+ if(common_config('db','quote_identifiers'))
+ $user_table = '"user"';
+ else $user_table = 'user';
$qry =
'SELECT id ' .
- 'FROM user JOIN group_member '.
- 'ON user.id = group_member.profile_id ' .
+ 'FROM '. $user_table .' JOIN group_member '.
+ 'ON '. $user_table .'.id = group_member.profile_id ' .
'WHERE group_member.group_id = %d ';
$user->query(sprintf($qry, $this->id));
diff --git a/db/laconica_pg.sql b/db/laconica_pg.sql
index dae8b8faf..31210fd1e 100644
--- a/db/laconica_pg.sql
+++ b/db/laconica_pg.sql
@@ -40,6 +40,19 @@ create table sms_carrier (
modified timestamp /* comment 'date this record was modified ' */
);
+create sequence design_seq;
+create table design (
+ id bigint default nextval('design_seq') /* comment 'design ID'*/,
+ backgroundcolor integer /* comment 'main background color'*/ ,
+ contentcolor integer /*comment 'content area background color'*/ ,
+ sidebarcolor integer /*comment 'sidebar background color'*/ ,
+ textcolor integer /*comment 'text color'*/ ,
+ linkcolor integer /*comment 'link color'*/,
+ backgroundimage varchar(255) /*comment 'background image, if any'*/,
+ disposition int default 1 /*comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'*/,
+ primary key (id)
+);
+
/* local users */
create table "user" (
@@ -71,6 +84,8 @@ create table "user" (
autosubscribe integer default 0 /* comment 'automatically subscribe to users who subscribe to us' */,
urlshorteningservice varchar(50) default 'ur1.ca' /* comment 'service to use for auto-shortening URLs' */,
inboxed integer default 0 /* comment 'has an inbox been created for this user?' */,
+ design_id integer /* comment 'id of a design' */references design(id),
+ viewdesigns integer default 1 /* comment 'whether to view user-provided designs'*/,
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */
@@ -184,7 +199,7 @@ create table token (
create table nonce (
consumer_key varchar(255) not null /* comment 'unique identifier, root URL' */,
- tok char(32) not null /* comment 'identifying value' */,
+ tok char(32) /* comment 'buggy old value, ignored' */,
nonce char(32) null /* comment 'buggy old value, ignored */,
ts integer not null /* comment 'timestamp sent' values are epoch, and only used internally */,
@@ -390,6 +405,8 @@ create table user_group (
homepage_logo varchar(255) /* comment 'homepage (profile) size logo' */,
stream_logo varchar(255) /* comment 'stream-sized logo' */,
mini_logo varchar(255) /* comment 'mini logo' */,
+ design_id integer /*comment 'id of a design' */ references design(id),
+
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */
@@ -424,7 +441,6 @@ create table group_inbox (
group_id integer not null /* comment 'group receiving the message' references user_group (id) */,
notice_id integer not null /* comment 'notice received' references notice (id) */,
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
-
primary key (group_id, notice_id)
);
create index group_inbox_created_idx on group_inbox using btree(created);
@@ -439,13 +455,14 @@ create table file (
size integer,
title varchar(255),
date integer,
- protected integer
+ protected integer,
+ filename text /* comment 'if a local file, name of the file' */,
+ modified timestamp default CURRENT_TIMESTAMP /* comment 'date this record was modified'*/
);
create sequence file_oembed_seq;
create table file_oembed (
- id bigint default nextval('file_oembed_seq') primary key /* comment 'unique identifier' */,
- file_id bigint unique,
+ file_id bigint default nextval('file_oembed_seq') primary key /* comment 'unique identifier' */,
version varchar(20),
type varchar(20),
provider varchar(50),
@@ -461,8 +478,7 @@ create table file_oembed (
create sequence file_redirection_seq;
create table file_redirection (
- id bigint default nextval('file_redirection_seq') primary key /* comment 'unique identifier' */,
- url varchar(255) unique,
+ url varchar(255) primary key,
file_id bigint,
redirections integer,
httpcode integer
@@ -470,8 +486,7 @@ create table file_redirection (
create sequence file_thumbnail_seq;
create table file_thumbnail (
- id bigint default nextval('file_thumbnail_seq') primary key /* comment 'unique identifier' */,
- file_id bigint unique,
+ file_id bigint primary key,
url varchar(255) unique,
width integer,
height integer
@@ -479,25 +494,31 @@ create table file_thumbnail (
create sequence file_to_post_seq;
create table file_to_post (
- id bigint default nextval('file_to_post_seq') primary key /* comment 'unique identifier' */,
file_id bigint,
post_id bigint,
- unique(file_id, post_id)
+ primary key (file_id, post_id)
);
-create sequence design_seq;
-create table design (
- id bigint default nextval('design_seq') /* comment 'design ID'*/,
- backgroundcolor integer /* comment 'main background color'*/ ,
- contentcolor integer /*comment 'content area background color'*/ ,
- sidebarcolor integer /*comment 'sidebar background color'*/ ,
- textcolor integer /*comment 'text color'*/ ,
- linkcolor integer /*comment 'link color'*/,
- backgroundimage varchar(255) /*comment 'background image, if any'*/,
- disposition int default 1 /*comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'*/,
- primary key (id)
+create table group_block (
+ group_id integer not null /* comment 'group profile is blocked from' */ references user_group (id),
+ blocked integer not null /* comment 'profile that is blocked' */references profile (id),
+ blocker integer not null /* comment 'user making the block'*/ references "user" (id),
+ modified timestamp /* comment 'date of blocking'*/ ,
+
+ primary key (group_id, blocked)
+);
+
+create table group_alias (
+
+ alias varchar(64) /* comment 'additional nickname for the group'*/ ,
+ group_id integer not null /* comment 'group profile is blocked from'*/ references user_group (id),
+ modified timestamp /* comment 'date alias was created'*/,
+ primary key (alias)
+
);
+create index group_alias_group_id_idx on group_alias (group_id);
+
/* Textsearch stuff */
diff --git a/db/sms_carrier.sql b/db/sms_carrier.sql
index 6879f2089..055606f58 100644
--- a/db/sms_carrier.sql
+++ b/db/sms_carrier.sql
@@ -60,4 +60,5 @@ VALUES
(100112, 'Cincinnati Bell Wireless', '%s@gocbw.com', now()),
(100113, 'T-Mobile Germany', '%s@t-mobile-sms.de', now()),
(100114, 'Vodafone Germany', '%s@vodafone-sms.de', now()),
- (100115, 'E-Plus', '%s@smsmail.eplus.de', now());
+ (100115, 'E-Plus', '%s@smsmail.eplus.de', now()),
+ (100116, 'Cellular South', '%s@csouth1.com', now());
diff --git a/extlib/Services/oEmbed.php b/extlib/Services/oEmbed.php
index 5d38ed883..7d507b6f6 100644
--- a/extlib/Services/oEmbed.php
+++ b/extlib/Services/oEmbed.php
@@ -162,7 +162,7 @@ class Services_oEmbed
}
if ($this->options[self::OPTION_API] === null) {
- $this->options[self::OPTION_API] = $this->discover();
+ $this->options[self::OPTION_API] = $this->discover($url);
}
}
@@ -319,7 +319,7 @@ class Services_oEmbed
}
}
- return (isset($ret['json']) ? $ret['json'] : array_pop($ret));
+ return (isset($ret['application/json']) ? $ret['application/json'] : array_pop($ret));
}
/**
diff --git a/htaccess.sample b/htaccess.sample
index 634900dbf..942e98334 100644
--- a/htaccess.sample
+++ b/htaccess.sample
@@ -1,12 +1,14 @@
-RewriteEngine On
+<IfModule mod_rewrite.c>
+ RewriteEngine On
-# NOTE: change this to your actual Laconica path; may be "/".
+ # NOTE: change this to your actual Laconica path; may be "/".
-RewriteBase /mublog/
+ RewriteBase /mublog/
-RewriteCond %{REQUEST_FILENAME} !-f
-RewriteCond %{REQUEST_FILENAME} !-d
-RewriteRule (.*) index.php?p=$1 [L,QSA]
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteRule (.*) index.php?p=$1 [L,QSA]
+</IfModule>
<FilesMatch "\.(ini)">
Order allow,deny
diff --git a/index.php b/index.php
index 5f9a048f2..69c0bc1b2 100644
--- a/index.php
+++ b/index.php
@@ -165,7 +165,8 @@ function main()
if (!$user && common_config('site', 'private') &&
!in_array($action, array('login', 'openidlogin', 'finishopenidlogin',
- 'recoverpassword', 'api', 'doc', 'register'))) {
+ 'recoverpassword', 'api', 'doc', 'register')) &&
+ !preg_match('/rss$/', $action)) {
common_redirect(common_local_url('login'));
return;
}
diff --git a/install.php b/install.php
index 570b08edf..1d3a531c5 100644
--- a/install.php
+++ b/install.php
@@ -43,12 +43,12 @@ function checkPrereqs()
$pass = false;
}
- if (version_compare(PHP_VERSION, '5.0.0', '<')) {
- ?><p class="error">Require PHP version 5 or greater.</p><?php
+ if (version_compare(PHP_VERSION, '5.2.3', '<')) {
+ ?><p class="error">Require PHP version 5.2.3 or greater.</p><?php
$pass = false;
}
- $reqs = array('gd', 'mysql', 'curl',
+ $reqs = array('gd', 'curl',
'xmlwriter', 'mbstring',
'gettext');
@@ -58,6 +58,10 @@ function checkPrereqs()
$pass = false;
}
}
+ if (!checkExtension('pgsql') && !checkExtension('mysql')) {
+ ?><p class="error">Cannot find mysql or pgsql extension. You need one or the other: <code><?php echo $req; ?></code></p><?php
+ $pass = false;
+ }
if (!is_writable(INSTALLDIR)) {
?><p class="error">Cannot write config file to: <code><?php echo INSTALLDIR; ?></code></p>
@@ -66,17 +70,16 @@ function checkPrereqs()
$pass = false;
}
- if (!is_writable(INSTALLDIR.'/avatar/')) {
- ?><p class="error">Cannot write avatar directory: <code><?php echo INSTALLDIR; ?>/avatar/</code></p>
- <p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?>/avatar/</code></p>
- <?
- $pass = false;
- }
- if (!is_writable(INSTALLDIR.'/background/')) {
- ?><p class="error">Cannot write background directory: <code><?php echo INSTALLDIR; ?>/background/</code></p>
- <p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?>/background/</code></p>
- <?
- $pass = false;
+ // Check the subdirs used for file uploads
+ $fileSubdirs = array('avatar', 'background', 'file');
+ foreach ($fileSubdirs as $fileSubdir) {
+ $fileFullPath = INSTALLDIR."/$fileSubdir/";
+ if (!is_writable($fileFullPath)) {
+ ?><p class="error">Cannot write <?php echo $fileSubdir; ?> directory: <code><?php echo $fileFullPath; ?></code></p>
+ <p>On your server, try this command: <code>chmod a+w <?php echo $fileFullPath; ?></code></p>
+ <?
+ $pass = false;
+ }
}
return $pass;
@@ -127,7 +130,15 @@ function showForm()
<p class="form_guide">Database hostname</p>
</li>
<li>
- <label for="host">Database</label>
+
+ <label for="dbtype">Type</label>
+ <input type="radio" name="dbtype" id="fancy-mysql" value="mysql" checked='checked' /> MySQL<br />
+ <input type="radio" name="dbtype" id="dbtype-pgsql" value="pgsql" /> PostgreSQL<br />
+ <p class="form_guide">Database type</p>
+ </li>
+
+ <li>
+ <label for="database">Name</label>
<input type="text" id="database" name="database" />
<p class="form_guide">Database name</p>
</li>
@@ -139,7 +150,7 @@ function showForm()
<li>
<label for="password">Password</label>
<input type="password" id="password" name="password" />
- <p class="form_guide">Database password</p>
+ <p class="form_guide">Database password (optional)</p>
</li>
</ul>
<input type="submit" name="submit" class="submit" value="Submit" />
@@ -163,6 +174,7 @@ function handlePost()
<?php
$host = $_POST['host'];
+ $dbtype = $_POST['dbtype'];
$database = $_POST['database'];
$username = $_POST['username'];
$password = $_POST['password'];
@@ -191,64 +203,28 @@ function handlePost()
$fail = true;
}
- if (empty($password)) {
- updateStatus("No password specified.", true);
- $fail = true;
- }
+// if (empty($password)) {
+// updateStatus("No password specified.", true);
+// $fail = true;
+// }
if (empty($sitename)) {
updateStatus("No sitename specified.", true);
$fail = true;
}
- if($fail){
- showForm();
- return;
- }
-
- updateStatus("Starting installation...");
- updateStatus("Checking database...");
- $conn = mysql_connect($host, $username, $password);
- if (!$conn) {
- updateStatus("Can't connect to server '$host' as '$username'.", true);
- showForm();
- return;
- }
- updateStatus("Changing to database...");
- $res = mysql_select_db($database, $conn);
- if (!$res) {
- updateStatus("Can't change to database.", true);
- showForm();
- return;
- }
- updateStatus("Running database script...");
- $res = runDbScript(INSTALLDIR.'/db/laconica.sql', $conn);
- if ($res === false) {
- updateStatus("Can't run database script.", true);
- showForm();
- return;
- }
- foreach (array('sms_carrier' => 'SMS carrier',
- 'notice_source' => 'notice source',
- 'foreign_services' => 'foreign service')
- as $scr => $name) {
- updateStatus(sprintf("Adding %s data to database...", $name));
- $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn);
- if ($res === false) {
- updateStatus(sprintf("Can't run %d script.", $name), true);
+ if($fail){
showForm();
- return;
- }
- }
- updateStatus("Writing config file...");
- $sqlUrl = "mysqli://$username:$password@$host/$database";
- $res = writeConf($sitename, $sqlUrl, $fancy);
- if (!$res) {
- updateStatus("Can't write config file.", true);
- showForm();
return;
}
- updateStatus("Done!");
+
+ switch($dbtype) {
+ case 'mysql': mysql_db_installer($host, $database, $username, $password, $sitename);
+ break;
+ case 'pgsql': pgsql_db_installer($host, $database, $username, $password, $sitename);
+ break;
+ default:
+ }
if ($path) $path .= '/';
updateStatus("You can visit your <a href='/$path'>new Laconica site</a>.");
?>
@@ -256,7 +232,106 @@ function handlePost()
<?php
}
-function writeConf($sitename, $sqlUrl, $fancy)
+function pgsql_db_installer($host, $database, $username, $password, $sitename) {
+ $connstring = "dbname=$database host=$host user=$username";
+
+ //No password would mean trust authentication used.
+ if (!empty($password)) {
+ $connstring .= " password=$password";
+ }
+ updateStatus("Starting installation...");
+ updateStatus("Checking database...");
+ $conn = pg_connect($connstring);
+
+ updateStatus("Running database script...");
+ //wrap in transaction;
+ pg_query($conn, 'BEGIN');
+ $res = runDbScript(INSTALLDIR.'/db/laconica_pg.sql', $conn, 'pgsql');
+
+ if ($res === false) {
+ updateStatus("Can't run database script.", true);
+ showForm();
+ return;
+ }
+ foreach (array('sms_carrier' => 'SMS carrier',
+ 'notice_source' => 'notice source',
+ 'foreign_services' => 'foreign service')
+ as $scr => $name) {
+ updateStatus(sprintf("Adding %s data to database...", $name));
+ $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn, 'pgsql');
+ if ($res === false) {
+ updateStatus(sprintf("Can't run %d script.", $name), true);
+ showForm();
+ return;
+ }
+ }
+ pg_query($conn, 'COMMIT');
+
+ updateStatus("Writing config file...");
+ if (empty($password)) {
+ $sqlUrl = "pgsql://$username@$host/$database";
+ }
+ else {
+ $sqlUrl = "pgsql://$username:$password@$host/$database";
+ }
+ $res = writeConf($sitename, $sqlUrl, $fancy, 'pgsql');
+ if (!$res) {
+ updateStatus("Can't write config file.", true);
+ showForm();
+ return;
+ }
+ updateStatus("Done!");
+
+}
+
+function mysql_db_installer($host, $database, $username, $password, $sitename) {
+ updateStatus("Starting installation...");
+ updateStatus("Checking database...");
+
+ $conn = mysql_connect($host, $username, $password);
+ if (!$conn) {
+ updateStatus("Can't connect to server '$host' as '$username'.", true);
+ showForm();
+ return;
+ }
+ updateStatus("Changing to database...");
+ $res = mysql_select_db($database, $conn);
+ if (!$res) {
+ updateStatus("Can't change to database.", true);
+ showForm();
+ return;
+ }
+ updateStatus("Running database script...");
+ $res = runDbScript(INSTALLDIR.'/db/laconica.sql', $conn);
+ if ($res === false) {
+ updateStatus("Can't run database script.", true);
+ showForm();
+ return;
+ }
+ foreach (array('sms_carrier' => 'SMS carrier',
+ 'notice_source' => 'notice source',
+ 'foreign_services' => 'foreign service')
+ as $scr => $name) {
+ updateStatus(sprintf("Adding %s data to database...", $name));
+ $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn);
+ if ($res === false) {
+ updateStatus(sprintf("Can't run %d script.", $name), true);
+ showForm();
+ return;
+ }
+ }
+
+ updateStatus("Writing config file...");
+ $sqlUrl = "mysqli://$username:$password@$host/$database";
+ $res = writeConf($sitename, $sqlUrl, $fancy);
+ if (!$res) {
+ updateStatus("Can't write config file.", true);
+ showForm();
+ return;
+ }
+ updateStatus("Done!");
+ }
+function writeConf($sitename, $sqlUrl, $fancy, $type='mysql')
{
$res = file_put_contents(INSTALLDIR.'/config.php',
"<?php\n".
@@ -264,11 +339,13 @@ function writeConf($sitename, $sqlUrl, $fancy)
"\$config['site']['name'] = \"$sitename\";\n\n".
($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
"\$config['db']['database'] = \"$sqlUrl\";\n\n".
+ ($type == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n" .
+ "\$config['db']['type'] = \"$type\";\n\n" : '').
"?>");
return $res;
}
-function runDbScript($filename, $conn)
+function runDbScript($filename, $conn, $type='mysql')
{
$sql = trim(file_get_contents($filename));
$stmts = explode(';', $sql);
@@ -277,8 +354,13 @@ function runDbScript($filename, $conn)
if (!mb_strlen($stmt)) {
continue;
}
- $res = mysql_query($stmt, $conn);
+ if ($type == 'mysql') {
+ $res = mysql_query($stmt, $conn);
+ } elseif ($type=='pgsql') {
+ $res = pg_query($conn, $stmt);
+ }
if ($res === false) {
+ updateStatus("FAILED SQL: $stmt");
return $res;
}
}
diff --git a/lib/common.php b/lib/common.php
index 9d7954fa9..764c5a077 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -19,7 +19,7 @@
if (!defined('LACONICA')) { exit(1); }
-define('LACONICA_VERSION', '0.8.1dev');
+define('LACONICA_VERSION', '0.9.0dev');
define('AVATAR_PROFILE_SIZE', 96);
define('AVATAR_STREAM_SIZE', 48);
diff --git a/lib/daemon.php b/lib/daemon.php
index 9d89c63e7..231f5414e 100644
--- a/lib/daemon.php
+++ b/lib/daemon.php
@@ -24,6 +24,7 @@ if (!defined('LACONICA')) {
class Daemon
{
var $daemonize = true;
+ var $_id = 'generic';
function __construct($daemonize = true)
{
@@ -35,6 +36,16 @@ class Daemon
return null;
}
+ function get_id()
+ {
+ return $this->_id;
+ }
+
+ function set_id($id)
+ {
+ $this->_id = $id;
+ }
+
function background()
{
$pid = pcntl_fork();
diff --git a/lib/dbqueuemanager.php b/lib/dbqueuemanager.php
index 6e7172de0..1df5af6c1 100644
--- a/lib/dbqueuemanager.php
+++ b/lib/dbqueuemanager.php
@@ -55,7 +55,8 @@ class DBQueueManager extends QueueManager
{
while (true) {
$this->_log(LOG_DEBUG, 'Checking for notices...');
- $notice = $this->_nextItem($queue, null);
+ $timeout = $handler->timeout();
+ $notice = $this->_nextItem($queue, $timeout);
if (empty($notice)) {
$this->_log(LOG_DEBUG, 'No notices waiting; idling.');
// Nothing in the queue. Do you
@@ -87,7 +88,9 @@ class DBQueueManager extends QueueManager
do {
$qi = Queue_item::top($queue);
- if (!empty($qi)) {
+ if (empty($qi)) {
+ sleep(1);
+ } else {
$notice = Notice::staticGet('id', $qi->notice_id);
if (!empty($notice)) {
$result = $notice;
diff --git a/lib/groupsbymemberssection.php b/lib/groupsbymemberssection.php
index 963e21f15..ad4884bf8 100644
--- a/lib/groupsbymemberssection.php
+++ b/lib/groupsbymemberssection.php
@@ -48,7 +48,7 @@ class GroupsByMembersSection extends GroupSection
$qry = 'SELECT user_group.*, count(*) as value ' .
'FROM user_group JOIN group_member '.
'ON user_group.id = group_member.group_id ' .
- 'GROUP BY user_group.id,user_group.nickname,user_group.fullname,user_group.homepage,user_group.description,user_group.location,user_group.original_logo,user_group.homepage_logo,user_group.stream_logo,user_group.mini_logo,user_group.created,user_group.modified ' .
+ 'GROUP BY user_group.id,user_group.nickname,user_group.fullname,user_group.homepage,user_group.description,user_group.location,user_group.original_logo,user_group.homepage_logo,user_group.stream_logo,user_group.mini_logo,user_group.created,user_group.modified,user_group.design_id ' .
'ORDER BY value DESC ';
$limit = GROUPS_PER_SECTION;
diff --git a/lib/groupsbypostssection.php b/lib/groupsbypostssection.php
index 325b4033f..dc7925d5e 100644
--- a/lib/groupsbypostssection.php
+++ b/lib/groupsbypostssection.php
@@ -48,7 +48,7 @@ class GroupsByPostsSection extends GroupSection
$qry = 'SELECT user_group.*, count(*) as value ' .
'FROM user_group JOIN group_inbox '.
'ON user_group.id = group_inbox.group_id ' .
- 'GROUP BY user_group.id,user_group.nickname,user_group.fullname,user_group.homepage,user_group.description,user_group.location,user_group.original_logo,user_group.homepage_logo,user_group.stream_logo,user_group.mini_logo,user_group.created,user_group.modified ' .
+ 'GROUP BY user_group.id,user_group.nickname,user_group.fullname,user_group.homepage,user_group.description,user_group.location,user_group.original_logo,user_group.homepage_logo,user_group.stream_logo,user_group.mini_logo,user_group.created,user_group.modified,user_group.design_id ' .
'ORDER BY value DESC ';
$limit = GROUPS_PER_SECTION;
diff --git a/lib/grouptagcloudsection.php b/lib/grouptagcloudsection.php
index 9b7a10f6b..0e0cbdd63 100644
--- a/lib/grouptagcloudsection.php
+++ b/lib/grouptagcloudsection.php
@@ -73,7 +73,7 @@ class GroupTagCloudSection extends TagCloudSection
$quoted = array();
foreach ($names as $name) {
- $quoted[] = "\"$name\"";
+ $quoted[] = "'$name'";
}
$namestring = implode(',', $quoted);
diff --git a/lib/language.php b/lib/language.php
index 3ea3dd2aa..9ad2d31bd 100644
--- a/lib/language.php
+++ b/lib/language.php
@@ -53,7 +53,7 @@ function client_prefered_language($httplang)
if (!empty($httplang[2][$i])) {
// if no q default to 1.0
$client_langs[$httplang[2][$i]] =
- ($httplang[6][$i]? (float) $httplang[6][$i] : 1.0);
+ ($httplang[6][$i]? (float) $httplang[6][$i] : 1.0 - ($i*0.01));
}
if (!empty($httplang[3][$i]) && empty($client_langs[$httplang[3][$i]])) {
// if a catchall default 0.01 lower
diff --git a/lib/mail.php b/lib/mail.php
index 90ee3c992..262f788ee 100644
--- a/lib/mail.php
+++ b/lib/mail.php
@@ -121,7 +121,7 @@ function mail_notify_from()
$domain = mail_domain();
- $notifyfrom = common_config('site', 'name') .' <noreply@'.$domain.'>';
+ $notifyfrom = '"'.common_config('site', 'name') .'" <noreply@'.$domain.'>';
}
return $notifyfrom;
diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php
index e47c9b385..167a6ff8d 100644
--- a/lib/popularnoticesection.php
+++ b/lib/popularnoticesection.php
@@ -74,11 +74,7 @@ class PopularNoticeSection extends NoticeSection
$offset = 0;
$limit = NOTICES_PER_SECTION + 1;
- if (common_config('db', 'type') == 'pgsql') {
- $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
- } else {
- $qry .= ' LIMIT ' . $offset . ', ' . $limit;
- }
+ $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
$notice = Memcached_DataObject::cachedQuery('Notice',
sprintf($qry, common_config('popular', 'dropoff')),
diff --git a/lib/queuehandler.php b/lib/queuehandler.php
index c2ff10f32..f11e5bd90 100644
--- a/lib/queuehandler.php
+++ b/lib/queuehandler.php
@@ -29,7 +29,6 @@ define('QUEUE_HANDLER_HIT_IDLE', 0);
class QueueHandler extends Daemon
{
- var $_id = 'generic';
function __construct($id=null, $daemonize=true)
{
@@ -55,16 +54,6 @@ class QueueHandler extends Daemon
return strtolower($this->class_name().'.'.$this->get_id());
}
- function get_id()
- {
- return $this->_id;
- }
-
- function set_id($id)
- {
- $this->_id = $id;
- }
-
function transport()
{
return null;
diff --git a/lib/router.php b/lib/router.php
index e12138637..8e4836497 100644
--- a/lib/router.php
+++ b/lib/router.php
@@ -129,6 +129,11 @@ class Router
$m->connect('index.php?action=' . $action, array('action' => $action));
}
+ $m->connect('main/:method',
+ array('action' => 'api',
+ 'method' => 'oembed(.xml|.json)?',
+ 'apiaction' => 'oembed'));
+
// settings
foreach (array('profile', 'avatar', 'password', 'openid', 'im',
@@ -206,7 +211,7 @@ class Router
array('tag' => '[a-zA-Z0-9]+'));
$m->connect('tag/:tag',
array('action' => 'tag'),
- array('tag' => '[a-zA-Z0-9]+'));
+ array('tag' => '[\pL\pN_\-\.]{1,64}'));
$m->connect('peopletag/:tag',
array('action' => 'peopletag'),
@@ -394,6 +399,10 @@ class Router
array('action' => 'api',
'apiaction' => 'laconica'));
+ $m->connect('api/laconica/:method',
+ array('action' => 'api',
+ 'apiaction' => 'laconica'));
+
// Groups
$m->connect('api/laconica/groups/:method/:argument',
array('action' => 'api',
diff --git a/lib/rssaction.php b/lib/rssaction.php
index ffa1f9e99..6c982705e 100644
--- a/lib/rssaction.php
+++ b/lib/rssaction.php
@@ -39,6 +39,7 @@ class Rss10Action extends Action
var $creators = array();
var $limit = DEFAULT_RSS_LIMIT;
var $notices = null;
+ var $tags_already_output = array();
/**
* Constructor
@@ -96,6 +97,31 @@ class Rss10Action extends Action
{
// Parent handling, including cache check
parent::handle($args);
+
+ if (common_config('site', 'private')) {
+ if (!isset($_SERVER['PHP_AUTH_USER'])) {
+
+ # This header makes basic auth go
+ header('WWW-Authenticate: Basic realm="Laconica RSS"');
+
+ # If the user hits cancel -- bam!
+ $this->show_basic_auth_error();
+ return;
+ } else {
+ $nickname = $_SERVER['PHP_AUTH_USER'];
+ $password = $_SERVER['PHP_AUTH_PW'];
+
+ if (!common_check_user($nickname, $password)) {
+ # basic authentication failed
+ list($proxy, $ip) = common_client_ip();
+
+ common_log(LOG_WARNING, "Failed RSS auth attempt, nickname = $nickname, proxy = $proxy, ip = $ip.");
+ $this->show_basic_auth_error();
+ return;
+ }
+ }
+ }
+
// Get the list of notices
if (empty($this->tag)) {
$this->notices = $this->getNotices($this->limit);
@@ -105,6 +131,18 @@ class Rss10Action extends Action
$this->showRss();
}
+ function show_basic_auth_error()
+ {
+ header('HTTP/1.1 401 Unauthorized');
+ header('Content-Type: application/xml; charset=utf-8');
+ $this->startXML();
+ $this->elementStart('hash');
+ $this->element('error', null, 'Could not authenticate you.');
+ $this->element('request', null, $_SERVER['REQUEST_URI']);
+ $this->elementEnd('hash');
+ $this->endXML();
+ }
+
/**
* Get the notices to output in this stream
*
@@ -192,24 +230,6 @@ class Rss10Action extends Action
}
}
- // XXX: Surely there should be a common function to do this?
- function extract_tags ($string)
- {
- $count = preg_match_all('/(?:^|\s)#([A-Za-z0-9_\-\.]{1,64})/', strtolower($string), $match);
- if (!count)
- {
- return array();
- }
-
- $rv = array();
- foreach ($match[1] as $tag)
- {
- $rv[] = common_canonical_tag($tag);
- }
-
- return array_unique($rv);
- }
-
function showItem($notice)
{
$profile = Profile::staticGet($notice->profile_id);
@@ -234,6 +254,11 @@ class Rss10Action extends Action
$replyurl = common_local_url('shownotice', array('notice' => $notice->reply_to));
$this->element('sioc:reply_of', array('rdf:resource' => $replyurl));
}
+ if (!empty($notice->conversation)) {
+ $conversationurl = common_local_url('conversation',
+ array('id' => $notice->conversation));
+ $this->element('sioc:has_discussion', array('rdf:resource' => $conversationurl));
+ }
$attachments = $notice->attachments();
if($attachments){
foreach($attachments as $attachment){
@@ -263,18 +288,28 @@ class Rss10Action extends Action
$this->element('sioc:links_to', array('rdf:resource'=>$attachment->url));
}
}
- $tags = $this->extract_tags($notice->content);
- if (!empty($tags)) {
- foreach ($tags as $tag)
- {
- $tagpage = common_local_url('tag', array('tag' => $tag));
- $tagrss = common_local_url('tagrss', array('tag' => $tag));
+
+ $tag = new Notice_tag();
+ $tag->notice_id = $notice->id;
+ if ($tag->find()) {
+ $entry['tags']=array();
+ while ($tag->fetch()) {
+ $tagpage = common_local_url('tag', array('tag' => $tag->tag));
+
+ if ( in_array($tag, $this->tags_already_output) ) {
+ $this->element('ctag:tagged', array('rdf:resource'=>$tagpage.'#concept'));
+ continue;
+ }
+
+ $tagrss = common_local_url('tagrss', array('tag' => $tag->tag));
$this->elementStart('ctag:tagged');
- $this->elementStart('ctag:Tag', array('rdf:about'=>$tagpage.'#concept', 'ctag:label'=>$tag));
+ $this->elementStart('ctag:Tag', array('rdf:about'=>$tagpage.'#concept', 'ctag:label'=>$tag->tag));
$this->element('foaf:page', array('rdf:resource'=>$tagpage));
$this->element('rdfs:seeAlso', array('rdf:resource'=>$tagrss));
$this->elementEnd('ctag:Tag');
$this->elementEnd('ctag:tagged');
+
+ $this->tags_already_output[] = $tag->tag;
}
}
$this->elementEnd('item');
@@ -320,6 +355,8 @@ class Rss10Action extends Action
'http://rdfs.org/sioc/ns#',
'xmlns:sioct' =>
'http://rdfs.org/sioc/types#',
+ 'xmlns:rdfs' =>
+ 'http://www.w3.org/2000/01/rdf-schema#',
'xmlns:laconica' =>
'http://laconi.ca/ont/',
'xmlns' => 'http://purl.org/rss/1.0/'));
diff --git a/lib/twitterapi.php b/lib/twitterapi.php
index 749083c7c..b2602e77c 100644
--- a/lib/twitterapi.php
+++ b/lib/twitterapi.php
@@ -186,21 +186,24 @@ class TwitterapiAction extends Action
$twitter_status['favorited'] = false;
}
- # Enclosures
+ // Enclosures
$attachments = $notice->attachments();
- $twitter_status['attachments']=array();
- if($attachments){
- foreach($attachments as $attachment){
- if ($attachment->isEnclosure()) {
- $enclosure=array();
- $enclosure['url']=$attachment->url;
- $enclosure['mimetype']=$attachment->mimetype;
- $enclosure['size']=$attachment->size;
- $twitter_status['attachments'][]=$enclosure;
- }
+ $enclosures = array();
+
+ foreach ($attachments as $attachment) {
+ if ($attachment->isEnclosure()) {
+ $enclosure = array();
+ $enclosure['url'] = $attachment->url;
+ $enclosure['mimetype'] = $attachment->mimetype;
+ $enclosure['size'] = $attachment->size;
+ $enclosures[] = $enclosure;
}
}
+ if (!empty($enclosures)) {
+ $twitter_status['attachments'] = $enclosures;
+ }
+
if ($include_user) {
# Don't get notice (recursive!)
$twitter_user = $this->twitter_user_array($profile, false);
@@ -215,7 +218,7 @@ class TwitterapiAction extends Action
$profile = $notice->getProfile();
$entry = array();
- # We trim() to avoid extraneous whitespace in the output
+ // We trim() to avoid extraneous whitespace in the output
$entry['content'] = common_xml_safe_str(trim($notice->rendered));
$entry['title'] = $profile->nickname . ': ' . common_xml_safe_str(trim($notice->content));
@@ -228,7 +231,26 @@ class TwitterapiAction extends Action
$entry['updated'] = $entry['published'];
$entry['author'] = $profile->getBestName();
- # Enclosure
+ // Enclosures
+ $attachments = $notice->attachments();
+ $enclosures = array();
+
+ foreach ($attachments as $attachment) {
+ if ($attachment->isEnclosure()) {
+ $enclosure = array();
+ $enclosure['url'] = $attachment->url;
+ $enclosure['mimetype'] = $attachment->mimetype;
+ $enclosure['size'] = $attachment->size;
+ $enclosures[] = $enclosure;
+ }
+ }
+
+ if (!empty($enclosures)) {
+ $entry['enclosures'] = $enclosures;
+ }
+
+/*
+ // Enclosure
$attachments = $notice->attachments();
if($attachments){
$entry['enclosures']=array();
@@ -242,8 +264,20 @@ class TwitterapiAction extends Action
}
}
}
+*/
- # RSS Item specific
+ // Tags/Categories
+ $tag = new Notice_tag();
+ $tag->notice_id = $notice->id;
+ if ($tag->find()) {
+ $entry['tags']=array();
+ while ($tag->fetch()) {
+ $entry['tags'][]=$tag->tag;
+ }
+ }
+ $tag->free();
+
+ // RSS Item specific
$entry['description'] = $entry['content'];
$entry['pubDate'] = common_date_rfc2822($notice->created);
$entry['guid'] = $entry['link'];
@@ -369,6 +403,9 @@ class TwitterapiAction extends Action
case 'text':
$this->element($element, null, common_xml_safe_str($value));
break;
+ case 'attachments':
+ $this->show_xml_attachments($twitter_status['attachments']);
+ break;
default:
$this->element($element, null, $value);
}
@@ -389,6 +426,20 @@ class TwitterapiAction extends Action
$this->elementEnd($role);
}
+ function show_xml_attachments($attachments) {
+ if (!empty($attachments)) {
+ $this->elementStart('attachments', array('type' => 'array'));
+ foreach ($attachments as $attachment) {
+ $attrs = array();
+ $attrs['url'] = $attachment['url'];
+ $attrs['mimetype'] = $attachment['mimetype'];
+ $attrs['size'] = $attachment['size'];
+ $this->element('enclosure', $attrs, '');
+ }
+ $this->elementEnd('attachments');
+ }
+ }
+
function show_twitter_rss_item($entry)
{
$this->elementStart('item');
@@ -403,6 +454,12 @@ class TwitterapiAction extends Action
$enclosure = $entry['enclosures'][0];
$this->element('enclosure', array('url'=>$enclosure['url'],'type'=>$enclosure['mimetype'],'length'=>$enclosure['size']), null);
}
+
+ if($entry['tags']){
+ foreach($entry['tags'] as $tag){
+ $this->element('category', null,$tag);
+ }
+ }
$this->elementEnd('item');
}
diff --git a/lib/util.php b/lib/util.php
index 9e8ec41d2..c7c82dba2 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -404,7 +404,7 @@ function common_render_text($text)
$r = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $r);
$r = common_replace_urls_callback($r, 'common_linkify');
- $r = preg_replace('/(^|\(|\[|\s+)#([A-Za-z0-9_\-\.]{1,64})/e', "'\\1#'.common_tag_link('\\2')", $r);
+ $r = preg_replace('/(^|\(|\[|\s+)#([\pL\pN_\-\.]{1,64})/e', "'\\1#'.common_tag_link('\\2')", $r);
// XXX: machine tags
return $r;
}
@@ -414,9 +414,9 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) {
$regex = '#'.
'(?:'.
'(?:'.
- '(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|xmpp|irc)://'.
+ '(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|irc)://'.
'|'.
- '(?:mailto|aim|tel):'.
+ '(?:mailto|aim|tel|xmpp):'.
')'.
'[^.\s]+\.[^\s]+'.
'|'.
diff --git a/scripts/getvaliddaemons.php b/scripts/getvaliddaemons.php
index 97c230784..1e4546dff 100755
--- a/scripts/getvaliddaemons.php
+++ b/scripts/getvaliddaemons.php
@@ -28,7 +28,8 @@
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$helptext = <<<ENDOFHELP
-getvaliddaemons.php - print out the currently configured PID directory
+getvaliddaemons.php - print out a list of valid daemons that should be started
+by the startdaemons script
ENDOFHELP;
diff --git a/scripts/maildaemon.php b/scripts/maildaemon.php
index 11ddf06b7..a4003b6b2 100755
--- a/scripts/maildaemon.php
+++ b/scripts/maildaemon.php
@@ -299,25 +299,40 @@ class MailerDaemon
$attachments = array();
+ $this->extract_part($parsed,$msg,$attachments);
+
+ return array($from, $to, $msg, $attachments);
+ }
+
+ function extract_part($parsed,&$msg,&$attachments){
if ($parsed->ctype_primary == 'multipart') {
- foreach ($parsed->parts as $part) {
- if ($part->ctype_primary == 'text' &&
- $part->ctype_secondary == 'plain') {
- $msg = $part->body;
- }else{
- if ($part->body) {
- $attachment = tmpfile();
- fwrite($attachment, $part->body);
- $attachments[] = $attachment;
- }
+ if($parsed->ctype_secondary == 'alternative'){
+ $altmsg = $this->extract_msg_from_multipart_alternative_part($parsed);
+ if(!empty($altmsg)) $msg = $altmsg;
+ }else{
+ foreach($parsed->parts as $part){
+ $this->extract_part($part,$msg,$attachments);
}
}
- } else if ($type == 'text/plain') {
+ } else if ($parsed->ctype_primary == 'text'
+ && $parsed->ctype_secondary=='plain') {
$msg = $parsed->body;
- } else {
- $this->unsupported_type($type);
+ }else if(!empty($parsed->body)){
+ if(common_config('attachments', 'uploads')){
+ //only save attachments if uploads are enabled
+ $attachment = tmpfile();
+ fwrite($attachment, $parsed->body);
+ $attachments[] = $attachment;
+ }
}
- return array($from, $to, $msg, $attachments);
+ }
+
+ function extract_msg_from_multipart_alternative_part($parsed){
+ foreach ($parsed->parts as $part) {
+ $this->extract_part($part,$msg,$attachments);
+ }
+ //we don't want any attachments that are a result of this parsing
+ return $msg;
}
function unsupported_type($type)
diff --git a/scripts/twitterstatusfetcher.php b/scripts/twitterstatusfetcher.php
index 8b10bfbad..e2ba1d003 100755
--- a/scripts/twitterstatusfetcher.php
+++ b/scripts/twitterstatusfetcher.php
@@ -25,19 +25,18 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('MAXCHILDREN', 2);
define('POLL_INTERVAL', 60); // in seconds
-$shortoptions = 'i::';
-$longoptions = array('id::');
+$shortoptions = 'di::';
+$longoptions = array('id::', 'debug');
$helptext = <<<END_OF_TRIM_HELP
Batch script for retrieving Twitter messages from foreign service.
- -i --id Identity (default 'generic')
-
-END_OF_TRIM_HELP;
+ -i --id Identity (default 'generic')
+ -d --debug Debug (lots of log output)
-require_once INSTALLDIR.'/scripts/commandline.inc';
+END_OF_TRIM_HELP;
-require_once INSTALLDIR . '/lib/common.php';
+require_once INSTALLDIR .'/scripts/commandline.inc';
require_once INSTALLDIR . '/lib/daemon.php';
/**
@@ -61,6 +60,15 @@ class TwitterStatusFetcher extends Daemon
{
private $_children = array();
+ function __construct($id=null, $daemonize=true)
+ {
+ parent::__construct($daemonize);
+
+ if ($id) {
+ $this->set_id($id);
+ }
+ }
+
/**
* Name of this daemon
*
@@ -80,6 +88,11 @@ class TwitterStatusFetcher extends Daemon
function run()
{
+ if (defined('SCRIPT_DEBUG')) {
+ common_debug($this->name() .
+ ': debugging log output enabled.');
+ }
+
do {
$flinks = $this->refreshFlinks();
@@ -640,6 +653,10 @@ if (have_option('i')) {
$id = null;
}
+if (have_option('d') || have_option('debug')) {
+ define('SCRIPT_DEBUG', true);
+}
+
$fetcher = new TwitterStatusFetcher($id);
$fetcher->runOnce();
diff --git a/scripts/xmppdaemon.php b/scripts/xmppdaemon.php
index 488b4b514..69512f243 100755
--- a/scripts/xmppdaemon.php
+++ b/scripts/xmppdaemon.php
@@ -175,6 +175,10 @@ class XMPPDaemon extends Daemon
$user = $this->get_user($from);
+ // For common_current_user to work
+ global $_cur;
+ $_cur = $user;
+
if (!$user) {
$this->from_site($from, 'Unknown user; go to ' .
common_local_url('imsettings') .
@@ -211,6 +215,7 @@ class XMPPDaemon extends Daemon
$user->free();
unset($user);
+ unset($_cur);
unset($pl['xml']);
$pl['xml'] = null;
diff --git a/theme/base/css/ie6.css b/theme/base/css/ie6.css
index dde4d6fc7..eca240faa 100644
--- a/theme/base/css/ie6.css
+++ b/theme/base/css/ie6.css
@@ -12,7 +12,7 @@ margin:0 auto;
}
#content {
-width:70%;
+width:69%;
}
#aside_primary {
padding:5%;
diff --git a/theme/cloudy/css/display.css b/theme/cloudy/css/display.css
index 12f186a56..82a1a1e4e 100644
--- a/theme/cloudy/css/display.css
+++ b/theme/cloudy/css/display.css
@@ -12,12 +12,12 @@ img { display:block; border:0; }
a abbr { cursor: pointer; border-bottom:0; }
table { border-collapse:collapse; }
ol { list-style-position:inside; }
-html { font-size: 100%; background-color:#fff; }
+html { font-size: 87.5%; }
body {
background-color:#fff;
color:#000;
font-family:sans-serif;
-font-size:0.75em;
+font-size:1em;
line-height:normal;
position:relative;
height:100%;
@@ -471,6 +471,24 @@ margin-bottom:7px;
#form_notice #notice_submit label {
display:none;
}
+#form_notice label[for=notice_data-attach],
+#form_notice #notice_data-attach {
+position:absolute;
+top:87px;
+cursor:pointer;
+}
+#form_notice label[for=notice_data-attach] {
+text-indent:-9999px;
+left:82%;
+width:16px;
+height:16px;
+}
+#form_notice #notice_data-attach {
+left:34.6%;
+padding:0;
+height:16px;
+}
+
#form_notice .form_note {
position:absolute;
top:-10px;
@@ -488,6 +506,7 @@ font-weight:bold;
line-height:1.15;
padding:1px 2px;
}
+
#form_notice #notice_action-submit {
width:14%;
height:35px;
@@ -505,6 +524,26 @@ margin-bottom:7px;
margin-left:18px;
float:left;
}
+#form_notice .error,
+#form_notice .success {
+float:left;
+clear:both;
+width:81.5%;
+margin-bottom:0;
+line-height:1.618;
+}
+#form_notice #notice_data-attach_selected code {
+float:left;
+width:90%;
+display:block;
+font-size:1.1em;
+line-height:1.8;
+overflow:auto;
+}
+#form_notice #notice_data-attach_selected button {
+float:right;
+font-size:0.8em;
+}
/* entity_profile */
@@ -746,17 +785,18 @@ float:left;
width:100%;
border-top-width:1px;
border-top-style:dotted;
-font-size:1.2em;
}
.notices li {
list-style-type:none;
line-height:1.1;
-width:94%;
-padding-right:5%;
-padding-left:1%;
min-height:47px;
}
-
+.notices .notices {
+margin-top:7px;
+margin-left:2%;
+width:98%;
+float:left;
+}
/* NOTICES */
#notices_primary {
@@ -805,13 +845,17 @@ text-decoration:underline;
.notice .entry-title {
float:none;
-display:inline;
-width:100%;
overflow:hidden;
+display:inline;
}
#shownotice .notice .entry-title {
font-size:2.2em;
}
+#conversation .notice .entry-title {
+display:block;
+width:90%;
+}
+
.notice p.entry-content {
display:inline;
@@ -887,13 +931,12 @@ outline:none;
.notice-options {
padding-left:2%;
float:left;
-width:50%;
font-size:0.95em;
-width:12.5%;
+width:16px;
float:right;
display:none;
}
-.notices li.hover div.notice-options {
+.notices li:hover div.notice-options {
display:block;
}
@@ -917,7 +960,7 @@ top:30px;
right:7px;
}
.notice-options .notice_delete {
-bottom:7px;
+top:47px;
right:7px;
}
.notice-options .notice_reply dt {
@@ -958,6 +1001,97 @@ border:0;
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:425px;
+}
+#jOverlayContent #content {
+border-radius:7px;
+-moz-border-radius:7px;
+-webkit-border-radius:7px;
+}
+#jOverlayLoading {
+top:5%;
+left:40%;
+}
+#attachment_view img {
+max-width:480px;
+max-height:480px;
+}
+#attachment_view #oembed_info {
+margin-top:11px;
+}
+#attachment_view #oembed_info dt,
+#attachment_view #oembed_info dd {
+float:left;
+}
+#attachment_view #oembed_info dt {
+clear:left;
+margin-right:11px;
+font-weight:bold;
+}
+#attachment_view #oembed_info dt:after {
+content: ":";
+}
#usergroups #new_group {
float: left;
@@ -1218,7 +1352,8 @@ clear:both;
#outbox.user_in #content,
#subscriptions.user_in #content,
#subscribers.user_in #content,
-#showgroup.user_in #content {
+#showgroup.user_in #content,
+#conversation.user_in #content {
padding-top:160px;
}
@@ -1243,6 +1378,14 @@ padding-top:160px;
display:none;
}
+#jOverlayContent #core #content {
+padding-top:11px;
+}
+#jOverlayContent #core {
+background:none;
+padding-top:0;
+}
+
html,
body,
@@ -1311,24 +1454,23 @@ border-top-color:#87B4C8;
}
-#content .notice p.entry-content a:visited {
-background-color:#fcfcfc;
-}
-#content .notice p.entry-content .vcard a {
-background-color:#fcfffc;
-}
-
#aside_primary {
background-color:#DDFFCC;
}
-
#notice_text-count {
-color:#333;
+color:#000000;
}
#form_notice.warning #notice_text-count {
-color:#000;
+color:#000000;
}
+#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;
@@ -1426,8 +1568,11 @@ background-image:url(../images/icons/twotone/green/shield.gif);
/* NOTICES */
-.notices li.over {
-background-color:#fcfcfc;
+.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,
@@ -1451,10 +1596,24 @@ background:transparent url(../images/icons/icon_trash.gif) no-repeat 0 45%;
.notices div.notice-options {
opacity:0.4;
}
-.notices li.hover div.entry-content,
-.notices li.hover div.notice-options {
+.notices li:hover div.entry-content,
+.notices li:hover div.notice-options {
opacity:1;
}
+.notices .notices {
+background-color:rgba(200, 200, 200, 0.01);
+}
+.notices .notices .notices {
+background-color:rgba(200, 200, 200, 0.02);
+}
+.notices .notices .notices .notices {
+background-color:rgba(200, 200, 200, 0.03);
+}
+.notices .notices .notices .notices .notices {
+background-color:rgba(200, 200, 200, 0.04);
+}
+
+
div.entry-content {
color:#333;
}
@@ -1462,8 +1621,11 @@ div.notice-options a,
div.notice-options input {
font-family:sans-serif;
}
-.notices li.hover {
-background-color:#fcfcfc;
+#content .notices li:hover {
+background-color:rgba(240, 240, 240, 0.2);
+}
+#conversation .notices li:hover {
+background-color:transparent;
}
/*END: NOTICES */
diff --git a/theme/cloudy/css/ie.css b/theme/cloudy/css/ie.css
index 095122100..94c2093b1 100644
--- a/theme/cloudy/css/ie.css
+++ b/theme/cloudy/css/ie.css
@@ -8,6 +8,16 @@ color:#fff;
background-color:#ddffcc;
}
+#form_notice .form_note + label {
+position:absolute;
+top:25px;
+left:83%;
+text-indent:-9999px;
+height:16px;
+width:16px;
+display:block;
+}
+
#aside_primary {
width:181px;
}
@@ -32,3 +42,13 @@ top:158px;
#subscribers #content {
padding-top:138px;
}
+
+.notice {
+z-index:1;
+}
+.notice:hover {
+z-index:9999;
+}
+.notice .thumbnail img {
+z-index:9999;
+}
diff --git a/theme/pigeonthoughts/css/base.css b/theme/pigeonthoughts/css/base.css
index 9866e2d2c..5d5eb9896 100644
--- a/theme/pigeonthoughts/css/base.css
+++ b/theme/pigeonthoughts/css/base.css
@@ -383,7 +383,7 @@ margin-bottom:1em;
}
#content {
-width:49.009%;
+width:50%;
min-height:259px;
float:left;
padding:0 18px;
@@ -402,7 +402,7 @@ float:left;
width:45.917%;
min-height:259px;
float:left;
-margin-left:1.385%;
+margin-left:0.25%;
padding-bottom:47px;
}
@@ -736,11 +736,10 @@ margin-right:11px;
.notice,
.profile {
position:relative;
-padding-top:11px;
-padding-bottom:11px;
+padding:11px 2%;
clear:both;
float:left;
-width:96.41%;
+width:95.7%;
border-width:1px;
border-style:solid;
margin-bottom:11px;
@@ -993,13 +992,36 @@ font-weight:bold;
padding:0;
}
#jOverlayContent h1 {
-max-width:475px;
+max-width:425px;
}
#jOverlayContent #content {
border-radius:7px;
-moz-border-radius:7px;
-webkit-border-radius:7px;
}
+#jOverlayLoading {
+top:5%;
+left:40%;
+}
+#attachment_view img {
+max-width:480px;
+max-height:480px;
+}
+#attachment_view #oembed_info {
+margin-top:11px;
+}
+#attachment_view #oembed_info dt,
+#attachment_view #oembed_info dd {
+float:left;
+}
+#attachment_view #oembed_info dt {
+clear:left;
+margin-right:11px;
+font-weight:bold;
+}
+#attachment_view #oembed_info dt:after {
+content: ":";
+}
#usergroups #new_group {
float: left;
@@ -1058,8 +1080,6 @@ top:3px;
left:3px;
}
-
-
.pagination {
float:left;
clear:both;
@@ -1105,7 +1125,6 @@ padding-right:30px;
}
/* END: NOTICE */
-
.hentry .entry-content p {
margin-bottom:18px;
}
@@ -1122,7 +1141,6 @@ margin-bottom:18px;
margin-left:18px;
}
-
/* TOP_POSTERS */
.section tbody td {
padding-right:11px;
@@ -1150,7 +1168,6 @@ margin-right:0;
display:none;
}
-
/* tagcloud */
.tag-cloud {
list-style-type:none;
@@ -1233,6 +1250,11 @@ clear:both;
margin-bottom:0;
}
+#form_settings_design #settings_design_background-image img {
+max-width:480px;
+max-height:480px;
+}
+
#form_settings_design #settings_design_color .form_data,
#form_settings_design #color-picker {
float:left;
diff --git a/theme/pigeonthoughts/css/display.css b/theme/pigeonthoughts/css/display.css
index 01af500bf..f113225fb 100644
--- a/theme/pigeonthoughts/css/display.css
+++ b/theme/pigeonthoughts/css/display.css
@@ -14,7 +14,8 @@ background:url(../images/illustrations/illu_pigeons-01.png) no-repeat 0 100%;
}
body,
-a:active {
+a:active,
+#content {
background-color:#AEA187;
}
body {