Merge commit 'origin/0.8.x' into 0.9.x

This commit is contained in:
Eric Helgeson 2009-07-22 10:28:17 -05:00
commit 8293961064
19 changed files with 133 additions and 72 deletions

11
README
View File

@ -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 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. 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 4. You should also take this moment to make your avatar, background, and
writeable by the Web server. An insecure way to do this is: 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/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 You can also make the avatar, background, and file directories
group, as noted above. writeable by the Web server group, as noted above.
5. Create a database to hold your microblog data. Something like this 5. Create a database to hold your microblog data. Something like this
should work: should work:

View File

@ -194,6 +194,9 @@ class RecoverpasswordAction extends Action
'or your registered email address.')); 'or your registered email address.'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
$this->element('input', array('name' => 'recover',
'type' => 'hidden',
'value' => _('Recover')));
$this->submit('recover', _('Recover')); $this->submit('recover', _('Recover'));
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');

View File

@ -122,6 +122,7 @@ class File extends Memcached_DataObject
} }
function isRespectsQuota($user,$fileSize) { function isRespectsQuota($user,$fileSize) {
if ($fileSize > common_config('attachments', 'file_quota')) { if ($fileSize > common_config('attachments', 'file_quota')) {
return sprintf(_('No file may be larger than %d bytes ' . return sprintf(_('No file may be larger than %d bytes ' .
'and the file you sent was %d bytes. Try to upload a smaller version.'), 'and the file you sent was %d bytes. Try to upload a smaller version.'),
@ -135,8 +136,7 @@ class File extends Memcached_DataObject
if ($total > common_config('attachments', 'user_quota')) { 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')); return sprintf(_('A file this large would exceed your user quota of %d bytes.'), common_config('attachments', 'user_quota'));
} }
$query .= ' AND EXTRACT(month FROM file.modified) = EXTRACT(month FROM now()) and EXTRACT(year FROM file.modified) = EXTRACT(year FROM now())';
$query .= ' month(modified) = month(now()) and year(modified) = year(now())';
$this->query($query); $this->query($query);
$this->fetch(); $this->fetch();
$total = $this->total + $fileSize; $total = $this->total + $fileSize;

View File

@ -97,13 +97,21 @@ class Notice extends Memcached_DataObject
function saveTags() function saveTags()
{ {
/* extract all #hastags */ /* 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) { if (!$count) {
return true; 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 */ /* 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 */ /* elide characters we don't want in the tag */
$this->saveTag($hashtag); $this->saveTag($hashtag);
} }
@ -112,8 +120,6 @@ class Notice extends Memcached_DataObject
function saveTag($hashtag) function saveTag($hashtag)
{ {
$hashtag = common_canonical_tag($hashtag);
$tag = new Notice_tag(); $tag = new Notice_tag();
$tag->notice_id = $this->id; $tag->notice_id = $this->id;
$tag->tag = $hashtag; $tag->tag = $hashtag;

View File

@ -106,14 +106,11 @@ class Session extends Memcached_DataObject
{ {
self::logdeb("garbage collection (maxlifetime = $maxlifetime)"); self::logdeb("garbage collection (maxlifetime = $maxlifetime)");
$epoch = time() - $maxlifetime; $epoch = common_sql_date(time() - $maxlifetime);
$qry = 'DELETE FROM session ' .
'WHERE modified < "'.$epoch.'"';
$session = new Session(); $session = new Session();
$session->whereAdd('modified < "'.$epoch.'"');
$result = $session->query($qry); $result = $session->delete(DB_DATAOBJECT_WHEREADD_ONLY);
self::logdeb("garbage collection result = $result"); self::logdeb("garbage collection result = $result");
} }

View File

@ -441,7 +441,6 @@ create table group_inbox (
group_id integer not null /* comment 'group receiving the message' references user_group (id) */, 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) */, notice_id integer not null /* comment 'notice received' references notice (id) */,
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */, created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
primary key (group_id, notice_id) primary key (group_id, notice_id)
); );
create index group_inbox_created_idx on group_inbox using btree(created); create index group_inbox_created_idx on group_inbox using btree(created);
@ -456,7 +455,9 @@ create table file (
size integer, size integer,
title varchar(255), title varchar(255),
date integer, 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 sequence file_oembed_seq;

View File

@ -60,4 +60,5 @@ VALUES
(100112, 'Cincinnati Bell Wireless', '%s@gocbw.com', now()), (100112, 'Cincinnati Bell Wireless', '%s@gocbw.com', now()),
(100113, 'T-Mobile Germany', '%s@t-mobile-sms.de', now()), (100113, 'T-Mobile Germany', '%s@t-mobile-sms.de', now()),
(100114, 'Vodafone Germany', '%s@vodafone-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());

View File

@ -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} !-f
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?p=$1 [L,QSA] RewriteRule (.*) index.php?p=$1 [L,QSA]
</IfModule>
<FilesMatch "\.(ini)"> <FilesMatch "\.(ini)">
Order allow,deny Order allow,deny

View File

@ -165,7 +165,8 @@ function main()
if (!$user && common_config('site', 'private') && if (!$user && common_config('site', 'private') &&
!in_array($action, array('login', 'openidlogin', 'finishopenidlogin', !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')); common_redirect(common_local_url('login'));
return; return;
} }

View File

@ -70,17 +70,16 @@ function checkPrereqs()
$pass = false; $pass = false;
} }
if (!is_writable(INSTALLDIR.'/avatar/')) { // Check the subdirs used for file uploads
?><p class="error">Cannot write avatar directory: <code><?php echo INSTALLDIR; ?>/avatar/</code></p> $fileSubdirs = array('avatar', 'background', 'file');
<p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?>/avatar/</code></p> foreach ($fileSubdirs as $fileSubdir) {
<? $fileFullPath = INSTALLDIR."/$fileSubdir/";
$pass = false; if (!is_writable($fileFullPath)) {
} ?><p class="error">Cannot write <?php echo $fileSubdir; ?> directory: <code><?php echo $fileFullPath; ?></code></p>
if (!is_writable(INSTALLDIR.'/background/')) { <p>On your server, try this command: <code>chmod a+w <?php echo $fileFullPath; ?></code></p>
?><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;
<? }
$pass = false;
} }
return $pass; return $pass;

View File

@ -55,7 +55,8 @@ class DBQueueManager extends QueueManager
{ {
while (true) { while (true) {
$this->_log(LOG_DEBUG, 'Checking for notices...'); $this->_log(LOG_DEBUG, 'Checking for notices...');
$notice = $this->_nextItem($queue, null); $timeout = $handler->timeout();
$notice = $this->_nextItem($queue, $timeout);
if (empty($notice)) { if (empty($notice)) {
$this->_log(LOG_DEBUG, 'No notices waiting; idling.'); $this->_log(LOG_DEBUG, 'No notices waiting; idling.');
// Nothing in the queue. Do you // Nothing in the queue. Do you
@ -87,7 +88,9 @@ class DBQueueManager extends QueueManager
do { do {
$qi = Queue_item::top($queue); $qi = Queue_item::top($queue);
if (!empty($qi)) { if (empty($qi)) {
sleep(1);
} else {
$notice = Notice::staticGet('id', $qi->notice_id); $notice = Notice::staticGet('id', $qi->notice_id);
if (!empty($notice)) { if (!empty($notice)) {
$result = $notice; $result = $notice;

View File

@ -53,7 +53,7 @@ function client_prefered_language($httplang)
if (!empty($httplang[2][$i])) { if (!empty($httplang[2][$i])) {
// if no q default to 1.0 // if no q default to 1.0
$client_langs[$httplang[2][$i]] = $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 (!empty($httplang[3][$i]) && empty($client_langs[$httplang[3][$i]])) {
// if a catchall default 0.01 lower // if a catchall default 0.01 lower

View File

@ -121,7 +121,7 @@ function mail_notify_from()
$domain = mail_domain(); $domain = mail_domain();
$notifyfrom = common_config('site', 'name') .' <noreply@'.$domain.'>'; $notifyfrom = '"'.common_config('site', 'name') .'" <noreply@'.$domain.'>';
} }
return $notifyfrom; return $notifyfrom;

View File

@ -211,7 +211,7 @@ class Router
array('tag' => '[a-zA-Z0-9]+')); array('tag' => '[a-zA-Z0-9]+'));
$m->connect('tag/:tag', $m->connect('tag/:tag',
array('action' => 'tag'), array('action' => 'tag'),
array('tag' => '[a-zA-Z0-9]+')); array('tag' => '[\pL\pN_\-\.]{1,64}'));
$m->connect('peopletag/:tag', $m->connect('peopletag/:tag',
array('action' => 'peopletag'), array('action' => 'peopletag'),

View File

@ -97,6 +97,31 @@ class Rss10Action extends Action
{ {
// Parent handling, including cache check // Parent handling, including cache check
parent::handle($args); 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 // Get the list of notices
if (empty($this->tag)) { if (empty($this->tag)) {
$this->notices = $this->getNotices($this->limit); $this->notices = $this->getNotices($this->limit);
@ -106,6 +131,18 @@ class Rss10Action extends Action
$this->showRss(); $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 * Get the notices to output in this stream
* *
@ -193,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) function showItem($notice)
{ {
$profile = Profile::staticGet($notice->profile_id); $profile = Profile::staticGet($notice->profile_id);
@ -269,26 +288,28 @@ class Rss10Action extends Action
$this->element('sioc:links_to', array('rdf:resource'=>$attachment->url)); $this->element('sioc:links_to', array('rdf:resource'=>$attachment->url));
} }
} }
$tags = $this->extract_tags($notice->content);
if (!empty($tags)) { $tag = new Notice_tag();
foreach ($tags as $tag) $tag->notice_id = $notice->id;
{ if ($tag->find()) {
$tagpage = common_local_url('tag', array('tag' => $tag)); $entry['tags']=array();
while ($tag->fetch()) {
$tagpage = common_local_url('tag', array('tag' => $tag->tag));
if ( in_array($tag, $this->tags_already_output) ) { if ( in_array($tag, $this->tags_already_output) ) {
$this->element('ctag:tagged', array('rdf:resource'=>$tagpage.'#concept')); $this->element('ctag:tagged', array('rdf:resource'=>$tagpage.'#concept'));
continue; continue;
} }
$tagrss = common_local_url('tagrss', array('tag' => $tag)); $tagrss = common_local_url('tagrss', array('tag' => $tag->tag));
$this->elementStart('ctag:tagged'); $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('foaf:page', array('rdf:resource'=>$tagpage));
$this->element('rdfs:seeAlso', array('rdf:resource'=>$tagrss)); $this->element('rdfs:seeAlso', array('rdf:resource'=>$tagrss));
$this->elementEnd('ctag:Tag'); $this->elementEnd('ctag:Tag');
$this->elementEnd('ctag:tagged'); $this->elementEnd('ctag:tagged');
$this->tags_already_output[] = $tag; $this->tags_already_output[] = $tag->tag;
} }
} }
$this->elementEnd('item'); $this->elementEnd('item');

View File

@ -265,6 +265,18 @@ class TwitterapiAction extends Action
} }
} }
*/ */
// 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 // RSS Item specific
$entry['description'] = $entry['content']; $entry['description'] = $entry['content'];
$entry['pubDate'] = common_date_rfc2822($notice->created); $entry['pubDate'] = common_date_rfc2822($notice->created);
@ -442,6 +454,12 @@ class TwitterapiAction extends Action
$enclosure = $entry['enclosures'][0]; $enclosure = $entry['enclosures'][0];
$this->element('enclosure', array('url'=>$enclosure['url'],'type'=>$enclosure['mimetype'],'length'=>$enclosure['size']), null); $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'); $this->elementEnd('item');
} }

View File

@ -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 = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $r);
$r = common_replace_urls_callback($r, 'common_linkify'); $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 // XXX: machine tags
return $r; return $r;
} }
@ -414,9 +414,9 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) {
$regex = '#'. $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]+'. '[^.\s]+\.[^\s]+'.
'|'. '|'.

View File

@ -28,7 +28,8 @@
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$helptext = <<<ENDOFHELP $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; ENDOFHELP;

View File

@ -175,6 +175,10 @@ class XMPPDaemon extends Daemon
$user = $this->get_user($from); $user = $this->get_user($from);
// For common_current_user to work
global $_cur;
$_cur = $user;
if (!$user) { if (!$user) {
$this->from_site($from, 'Unknown user; go to ' . $this->from_site($from, 'Unknown user; go to ' .
common_local_url('imsettings') . common_local_url('imsettings') .
@ -211,6 +215,7 @@ class XMPPDaemon extends Daemon
$user->free(); $user->free();
unset($user); unset($user);
unset($_cur);
unset($pl['xml']); unset($pl['xml']);
$pl['xml'] = null; $pl['xml'] = null;