summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZach Copley <zach@controlyourself.ca>2009-06-29 13:23:45 -0700
committerZach Copley <zach@controlyourself.ca>2009-06-29 13:23:45 -0700
commitdd1fc46f0986e5675d24208199b88150f643925d (patch)
treeb19ecc1c4f60882f5cc231214398e57190d6ce14
parentf65015b24a8448ecbb12b3897992cdaf6b563212 (diff)
parent5b8e40aaa9bdb0c07cce0cf53cd913b0c397fdc4 (diff)
Merge branch '0.8.x' into design_reset
* 0.8.x: (32 commits) admin indicators in groups show section with admins in sidebar of group update to latest (r76) version of XMPPHP better output for common error handler fix logging error note when going background change name of constructor for xmppdaemon add a lot more logging to xmppdaemon error in get_option_value wasn't returning a value reformat commandline.inc if not in daemon mode, xmppdaemon sends log to stdout extract log-line formatting to its own function got my background/foreground logic backwards twitter status fetcher takes an id argument more efficient fixup of conversations commandline processing handles errors better xmppdaemon.php can stay in foreground command line arg handling a little more flexible Daemon can optionally not go into the background don't canonicalize people's text into URLs ... Conflicts: theme/base/css/display.css
-rw-r--r--README12
-rw-r--r--actions/api.php4
-rw-r--r--actions/groupmembers.php9
-rw-r--r--actions/showgroup.php44
-rw-r--r--classes/Notice.php2
-rw-r--r--classes/Session.php129
-rw-r--r--classes/Status_network.php7
-rw-r--r--classes/User_group.php24
-rw-r--r--[-rwxr-xr-x]classes/laconica.ini9
-rw-r--r--db/laconica.sql11
-rw-r--r--extlib/XMPPHP/BOSH.php2
-rw-r--r--extlib/XMPPHP/XMLStream.php8
-rw-r--r--extlib/XMPPHP/XMPP.php13
-rw-r--r--index.php48
-rw-r--r--lib/common.php3
-rw-r--r--lib/daemon.php21
-rw-r--r--lib/queuehandler.php5
-rw-r--r--lib/util.php108
-rw-r--r--scripts/commandline.inc84
-rwxr-xr-xscripts/fixup_conversations.php31
-rwxr-xr-xscripts/twitterstatusfetcher.php19
-rwxr-xr-xscripts/xmppdaemon.php62
-rw-r--r--theme/base/css/display.css17
23 files changed, 557 insertions, 115 deletions
diff --git a/README b/README
index 1a57d6a80..c8c529ed8 100644
--- a/README
+++ b/README
@@ -1278,6 +1278,18 @@ type: type of search. Ignored if PostgreSQL or Sphinx are enabled. Can either
systems. We'll probably add another type sometime in the future,
with our own indexing system (maybe like MediaWiki's).
+sessions
+--------
+
+Session handling.
+
+handle: boolean. Whether we should register our own PHP session-handling
+ code (using the database and memcache if enabled). Defaults to false.
+ Setting this to true makes some sense on large or multi-server
+ sites, but it probably won't hurt for smaller ones, either.
+debug: whether to output debugging info for session storage. Can help
+ with weird session bugs, sometimes. Default false.
+
Troubleshooting
===============
diff --git a/actions/api.php b/actions/api.php
index 1fe5875ad..08f5fadad 100644
--- a/actions/api.php
+++ b/actions/api.php
@@ -67,7 +67,9 @@ class ApiAction extends Action
$this->process_command();
} else {
# basic authentication failed
- common_log(LOG_WARNING, "Failed API auth attempt, nickname: $nickname.");
+ list($proxy, $ip) = common_client_ip();
+
+ common_log(LOG_WARNING, "Failed API auth attempt, nickname = $nickname, proxy = $proxy, ip = $ip.");
$this->show_basic_auth_error();
}
}
diff --git a/actions/groupmembers.php b/actions/groupmembers.php
index d132cdf96..be7a9e81c 100644
--- a/actions/groupmembers.php
+++ b/actions/groupmembers.php
@@ -167,6 +167,15 @@ class GroupMemberListItem extends ProfileListItem
$this->group = $group;
}
+ function showFullName()
+ {
+ parent::showFullName();
+ if ($this->profile->isAdmin($this->group)) {
+ $this->out->text(' ');
+ $this->out->element('span', 'admin_indicator', _('Admin'));
+ }
+ }
+
function showActions()
{
$this->startActions();
diff --git a/actions/showgroup.php b/actions/showgroup.php
index b6a0f4844..ce11d574e 100644
--- a/actions/showgroup.php
+++ b/actions/showgroup.php
@@ -331,6 +331,7 @@ class ShowgroupAction extends GroupDesignAction
{
$this->showMembers();
$this->showStatistics();
+ $this->showAdmins();
$cloud = new GroupTagCloudSection($this, $this->group);
$cloud->show();
}
@@ -370,6 +371,18 @@ class ShowgroupAction extends GroupDesignAction
}
/**
+ * Show list of admins
+ *
+ * @return void
+ */
+
+ function showAdmins()
+ {
+ $adminSection = new GroupAdminSection($this, $this->group);
+ $adminSection->show();
+ }
+
+ /**
* Show some statistics
*
* @return void
@@ -423,3 +436,34 @@ class ShowgroupAction extends GroupDesignAction
$this->elementEnd('div');
}
}
+
+class GroupAdminSection extends ProfileSection
+{
+ var $group;
+
+ function __construct($out, $group)
+ {
+ parent::__construct($out);
+ $this->group = $group;
+ }
+
+ function getProfiles()
+ {
+ return $this->group->getAdmins();
+ }
+
+ function title()
+ {
+ return _('Admins');
+ }
+
+ function divId()
+ {
+ return 'group_admins';
+ }
+
+ function moreUrl()
+ {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/classes/Notice.php b/classes/Notice.php
index d0ee1d925..502cc57b8 100644
--- a/classes/Notice.php
+++ b/classes/Notice.php
@@ -874,7 +874,6 @@ class Notice extends Memcached_DataObject
$qry .= '('.$id.', '.$this->id.', '.$source.', "'.$this->created.'") ';
$cnt++;
if ($cnt >= MAX_BOXCARS) {
- common_debug($qry);
$inbox = new Notice_inbox();
$inbox->query($qry);
$qry = $qryhdr;
@@ -883,7 +882,6 @@ class Notice extends Memcached_DataObject
}
if ($cnt > 0) {
- common_debug($qry);
$inbox = new Notice_inbox();
$inbox->query($qry);
}
diff --git a/classes/Session.php b/classes/Session.php
new file mode 100644
index 000000000..93fd99baa
--- /dev/null
+++ b/classes/Session.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * Table Definition for session
+ *
+ * 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/>.
+ */
+
+if (!defined('LACONICA')) { exit(1); }
+
+require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
+
+class Session extends Memcached_DataObject
+{
+ ###START_AUTOCODE
+ /* the code below is auto generated do not remove the above tag */
+
+ public $__table = 'session'; // table name
+ public $id; // varchar(32) primary_key not_null
+ public $session_data; // text()
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ /* Static get */
+ function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Session',$k,$v); }
+
+ /* the code above is auto generated do not remove the tag below */
+ ###END_AUTOCODE
+
+ static function logdeb($msg)
+ {
+ if (common_config('sessions', 'debug')) {
+ common_debug("Session: " . $msg);
+ }
+ }
+
+ static function open($save_path, $session_name)
+ {
+ return true;
+ }
+
+ static function close()
+ {
+ return true;
+ }
+
+ static function read($id)
+ {
+ self::logdeb("Fetching session '$id'");
+
+ $session = Session::staticGet('id', $id);
+
+ if (empty($session)) {
+ return '';
+ } else {
+ return (string)$session->session_data;
+ }
+ }
+
+ static function write($id, $session_data)
+ {
+ self::logdeb("Writing session '$id'");
+
+ $session = Session::staticGet('id', $id);
+
+ if (empty($session)) {
+ $session = new Session();
+
+ $session->id = $id;
+ $session->session_data = $session_data;
+ $session->created = common_sql_now();
+
+ return $session->insert();
+ } else {
+ $session->session_data = $session_data;
+
+ return $session->update();
+ }
+ }
+
+ static function destroy($id)
+ {
+ self::logdeb("Deleting session $id");
+
+ $session = Session::staticGet('id', $id);
+
+ if (!empty($session)) {
+ return $session->delete();
+ }
+ }
+
+ static function gc($maxlifetime)
+ {
+ self::logdeb("garbage collection (maxlifetime = $maxlifetime)");
+
+ $epoch = time() - $maxlifetime;
+
+ $qry = 'DELETE FROM session ' .
+ 'WHERE modified < "'.$epoch.'"';
+
+ $session = new Session();
+
+ $result = $session->query($qry);
+
+ self::logdeb("garbage collection result = $result");
+ }
+
+ static function setSaveHandler()
+ {
+ self::logdeb("setting save handlers");
+ $result = session_set_save_handler('Session::open', 'Session::close', 'Session::read',
+ 'Session::write', 'Session::destroy', 'Session::gc');
+ self::logdeb("save handlers result = $result");
+ return $result;
+ }
+}
diff --git a/classes/Status_network.php b/classes/Status_network.php
index f8d6756b6..dbd722e88 100644
--- a/classes/Status_network.php
+++ b/classes/Status_network.php
@@ -132,6 +132,13 @@ class Status_network extends DB_DataObject
}
} else {
$sn = self::memGet('hostname', strtolower($servername));
+
+ if (empty($sn)) {
+ // Try for a no-www address
+ if (0 == strncasecmp($servername, 'www.', 4)) {
+ $sn = self::memGet('hostname', strtolower(substr($servername, 4)));
+ }
+ }
}
if (!empty($sn)) {
diff --git a/classes/User_group.php b/classes/User_group.php
index 9b4b01ead..27b444705 100644
--- a/classes/User_group.php
+++ b/classes/User_group.php
@@ -126,6 +126,30 @@ class User_group extends Memcached_DataObject
return $members;
}
+ function getAdmins($offset=0, $limit=null)
+ {
+ $qry =
+ 'SELECT profile.* ' .
+ 'FROM profile JOIN group_member '.
+ 'ON profile.id = group_member.profile_id ' .
+ 'WHERE group_member.group_id = %d ' .
+ 'AND group_member.is_admin = 1 ' .
+ 'ORDER BY group_member.modified ASC ';
+
+ if ($limit != null) {
+ if (common_config('db','type') == 'pgsql') {
+ $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
+ } else {
+ $qry .= ' LIMIT ' . $offset . ', ' . $limit;
+ }
+ }
+
+ $admins = new Profile();
+
+ $admins->query(sprintf($qry, $this->id));
+ return $admins;
+ }
+
function getBlocked($offset=0, $limit=null)
{
$qry =
diff --git a/classes/laconica.ini b/classes/laconica.ini
index 7e9b2b791..766bed75d 100755..100644
--- a/classes/laconica.ini
+++ b/classes/laconica.ini
@@ -380,6 +380,15 @@ replied_id = 1
notice_id = K
profile_id = K
+[session]
+id = 130
+session_data = 34
+created = 142
+modified = 384
+
+[session__keys]
+id = K
+
[sms_carrier]
id = 129
name = 2
diff --git a/db/laconica.sql b/db/laconica.sql
index 3f8918de6..2c04f680a 100644
--- a/db/laconica.sql
+++ b/db/laconica.sql
@@ -524,3 +524,14 @@ create table group_alias (
index group_alias_group_id_idx (group_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+create table session (
+
+ id varchar(32) primary key comment 'session ID',
+ session_data text comment 'session data',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ index session_modified_idx (modified)
+
+) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; \ No newline at end of file
diff --git a/extlib/XMPPHP/BOSH.php b/extlib/XMPPHP/BOSH.php
index b147443d7..befaf60a7 100644
--- a/extlib/XMPPHP/BOSH.php
+++ b/extlib/XMPPHP/BOSH.php
@@ -27,7 +27,7 @@
*/
/** XMPPHP_XMLStream */
-require_once "XMPP.php";
+require_once dirname(__FILE__) . "/XMPP.php";
/**
* XMPPHP Main Class
diff --git a/extlib/XMPPHP/XMLStream.php b/extlib/XMPPHP/XMLStream.php
index 0fcfea375..d33411ec5 100644
--- a/extlib/XMPPHP/XMLStream.php
+++ b/extlib/XMPPHP/XMLStream.php
@@ -27,13 +27,13 @@
*/
/** XMPPHP_Exception */
-require_once 'Exception.php';
+require_once dirname(__FILE__) . '/Exception.php';
/** XMPPHP_XMLObj */
-require_once 'XMLObj.php';
+require_once dirname(__FILE__) . '/XMLObj.php';
/** XMPPHP_Log */
-require_once 'Log.php';
+require_once dirname(__FILE__) . '/Log.php';
/**
* XMPPHP XML Stream
@@ -375,7 +375,7 @@ class XMPPHP_XMLStream {
* integer -> process for this amount of time
*/
- private function __process($maximum=0) {
+ private function __process($maximum=5) {
$remaining = $maximum;
diff --git a/extlib/XMPPHP/XMPP.php b/extlib/XMPPHP/XMPP.php
index 73fbd2658..429f45e56 100644
--- a/extlib/XMPPHP/XMPP.php
+++ b/extlib/XMPPHP/XMPP.php
@@ -27,8 +27,8 @@
*/
/** XMPPHP_XMLStream */
-require_once "XMLStream.php";
-require_once "Roster.php";
+require_once dirname(__FILE__) . "/XMLStream.php";
+require_once dirname(__FILE__) . "/Roster.php";
/**
* XMPPHP Main Class
@@ -208,6 +208,15 @@ class XMPPHP_XMPP extends XMPPHP_XMLStream {
$this->send($out);
}
+ /**
+ * Send Auth request
+ *
+ * @param string $jid
+ */
+ public function subscribe($jid) {
+ $this->send("<presence type='subscribe' to='{$jid}' from='{$this->fulljid}' />");
+ #$this->send("<presence type='subscribed' to='{$jid}' from='{$this->fulljid}' />");
+ }
/**
* Message handler
diff --git a/index.php b/index.php
index cb6a0fe60..5f9a048f2 100644
--- a/index.php
+++ b/index.php
@@ -73,13 +73,45 @@ function handleError($error)
exit(-1);
}
+function checkMirror($action_obj)
+{
+ global $config;
+
+ static $alwaysRW = array('session', 'remember_me');
+
+ if (common_config('db', 'mirror') && $action_obj->isReadOnly($args)) {
+ if (is_array(common_config('db', 'mirror'))) {
+ // "load balancing", ha ha
+ $arr = common_config('db', 'mirror');
+ $k = array_rand($arr);
+ $mirror = $arr[$k];
+ } else {
+ $mirror = common_config('db', 'mirror');
+ }
+
+ // We ensure that these tables always are used
+ // on the master DB
+
+ $config['db']['database_rw'] = $config['db']['database'];
+ $config['db']['ini_rw'] = INSTALLDIR.'/classes/laconica.ini';
+
+ foreach ($alwaysRW as $table) {
+ $config['db']['table_'.$table] = 'rw';
+ }
+
+ // everyone else uses the mirror
+
+ $config['db']['database'] = $mirror;
+ }
+}
+
function main()
{
// quick check for fancy URL auto-detection support in installer.
if (isset($_SERVER['REDIRECT_URL']) && ((dirname($_SERVER['REQUEST_URI']) . '/check-fancy') === $_SERVER['REDIRECT_URL'])) {
die("Fancy URL support detection succeeded. We suggest you enable this to get fancy (pretty) URLs.");
}
- global $user, $action, $config;
+ global $user, $action;
Snapshot::check();
@@ -146,19 +178,7 @@ function main()
} else {
$action_obj = new $action_class();
- // XXX: find somewhere for this little block to live
-
- if (common_config('db', 'mirror') && $action_obj->isReadOnly($args)) {
- if (is_array(common_config('db', 'mirror'))) {
- // "load balancing", ha ha
- $arr = common_config('db', 'mirror');
- $k = array_rand($arr);
- $mirror = $arr[$k];
- } else {
- $mirror = common_config('db', 'mirror');
- }
- $config['db']['database'] = $mirror;
- }
+ checkMirror($action_obj);
try {
if ($action_obj->prepare($args)) {
diff --git a/lib/common.php b/lib/common.php
index bb1a4255d..e2936f075 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -254,6 +254,9 @@ $config =
'oohembed' => array('endpoint' => 'http://oohembed.com/oohembed/'),
'search' =>
array('type' => 'fulltext'),
+ 'sessions' =>
+ array('handle' => false, // whether to handle sessions ourselves
+ 'debug' => false), // debugging output for sessions
);
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
diff --git a/lib/daemon.php b/lib/daemon.php
index a0df00bdc..9d89c63e7 100644
--- a/lib/daemon.php
+++ b/lib/daemon.php
@@ -23,6 +23,13 @@ if (!defined('LACONICA')) {
class Daemon
{
+ var $daemonize = true;
+
+ function __construct($daemonize = true)
+ {
+ $this->daemonize = $daemonize;
+ }
+
function name()
{
return null;
@@ -129,12 +136,16 @@ class Daemon
common_log(LOG_INFO, $this->name() . ' already running. Exiting.');
exit(0);
}
- if ($this->background()) {
- $this->writePidFile();
- $this->changeUser();
- $this->run();
- $this->clearPidFile();
+
+ if ($this->daemonize) {
+ common_log(LOG_INFO, 'Backgrounding daemon "'.$this->name().'"');
+ $this->background();
}
+
+ $this->writePidFile();
+ $this->changeUser();
+ $this->run();
+ $this->clearPidFile();
}
function run()
diff --git a/lib/queuehandler.php b/lib/queuehandler.php
index ae403c65e..c1c4f3309 100644
--- a/lib/queuehandler.php
+++ b/lib/queuehandler.php
@@ -27,11 +27,12 @@ require_once(INSTALLDIR.'/classes/Notice.php');
class QueueHandler extends Daemon
{
-
var $_id = 'generic';
- function QueueHandler($id=null)
+ function __construct($id=null, $daemonize=true)
{
+ parent::__construct($daemonize);
+
if ($id) {
$this->set_id($id);
}
diff --git a/lib/util.php b/lib/util.php
index f6d50b180..f9ff38c8a 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -139,8 +139,23 @@ function common_have_session()
function common_ensure_session()
{
+ $c = null;
+ if (array_key_exists(session_name, $_COOKIE)) {
+ $c = $_COOKIE[session_name()];
+ }
if (!common_have_session()) {
+ if (common_config('sessions', 'handle')) {
+ common_log(LOG_INFO, "Using our own session handler");
+ Session::setSaveHandler();
+ }
@session_start();
+ if (!isset($_SESSION['started'])) {
+ $_SESSION['started'] = time();
+ if (!empty($c)) {
+ common_log(LOG_WARNING, 'Session cookie "' . $_COOKIE[session_name()] . '" ' .
+ ' is set but started value is null');
+ }
+ }
}
}
@@ -485,17 +500,19 @@ function common_linkify($url) {
// It comes in special'd, so we unspecial it before passing to the stringifying
// functions
$url = htmlspecialchars_decode($url);
- $display = File_redirection::_canonUrl($url);
+
+ $canon = File_redirection::_canonUrl($url);
+
$longurl_data = File_redirection::where($url);
if (is_array($longurl_data)) {
$longurl = $longurl_data['url'];
} elseif (is_string($longurl_data)) {
$longurl = $longurl_data;
} else {
- die('impossible to linkify');
+ throw new ServerException("Can't linkify url '$url'");
}
- $attrs = array('href' => $longurl, 'rel' => 'external');
+ $attrs = array('href' => $canon, 'rel' => 'external');
$is_attachment = false;
$attachment_id = null;
@@ -513,13 +530,13 @@ 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.
+ // 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;
@@ -549,7 +566,7 @@ function common_linkify($url) {
$attrs['id'] = "attachment-{$attachment_id}";
}
- return XMLStringer::estring('a', $attrs, $display);
+ return XMLStringer::estring('a', $attrs, $url);
}
function common_shorten_links($text)
@@ -817,7 +834,12 @@ function common_date_iso8601($dt)
function common_sql_now()
{
- return strftime('%Y-%m-%d %H:%M:%S', time());
+ return common_sql_date(time());
+}
+
+function common_sql_date($datetime)
+{
+ return strftime('%Y-%m-%d %H:%M:%S', $datetime);
}
function common_redirect($url, $code=307)
@@ -1082,15 +1104,20 @@ function common_ensure_syslog()
}
}
+function common_log_line($priority, $msg)
+{
+ static $syslog_priorities = array('LOG_EMERG', 'LOG_ALERT', 'LOG_CRIT', 'LOG_ERR',
+ 'LOG_WARNING', 'LOG_NOTICE', 'LOG_INFO', 'LOG_DEBUG');
+ return date('Y-m-d H:i:s') . ' ' . $syslog_priorities[$priority] . ': ' . $msg . "\n";
+}
+
function common_log($priority, $msg, $filename=null)
{
$logfile = common_config('site', 'logfile');
if ($logfile) {
$log = fopen($logfile, "a");
if ($log) {
- static $syslog_priorities = array('LOG_EMERG', 'LOG_ALERT', 'LOG_CRIT', 'LOG_ERR',
- 'LOG_WARNING', 'LOG_NOTICE', 'LOG_INFO', 'LOG_DEBUG');
- $output = date('Y-m-d H:i:s') . ' ' . $syslog_priorities[$priority] . ': ' . $msg . "\n";
+ $output = common_log_line($priority, $msg);
fwrite($log, $output);
fclose($log);
}
@@ -1321,18 +1348,39 @@ function common_canonical_sms($sms)
function common_error_handler($errno, $errstr, $errfile, $errline, $errcontext)
{
switch ($errno) {
+
+ case E_ERROR:
+ case E_COMPILE_ERROR:
+ case E_CORE_ERROR:
case E_USER_ERROR:
- common_log(LOG_ERR, "[$errno] $errstr ($errfile:$errline)");
- exit(1);
+ case E_PARSE:
+ case E_RECOVERABLE_ERROR:
+ common_log(LOG_ERR, "[$errno] $errstr ($errfile:$errline) [ABORT]");
+ die();
break;
+ case E_WARNING:
+ case E_COMPILE_WARNING:
+ case E_CORE_WARNING:
case E_USER_WARNING:
common_log(LOG_WARNING, "[$errno] $errstr ($errfile:$errline)");
break;
+ case E_NOTICE:
case E_USER_NOTICE:
common_log(LOG_NOTICE, "[$errno] $errstr ($errfile:$errline)");
break;
+
+ case E_STRICT:
+ case E_DEPRECATED:
+ case E_USER_DEPRECATED:
+ // XXX: config variable to log this stuff, too
+ break;
+
+ default:
+ common_log(LOG_ERR, "[$errno] $errstr ($errfile:$errline) [UNKNOWN LEVEL, die()'ing]");
+ die();
+ break;
}
// FIXME: show error page if we're on the Web
@@ -1470,4 +1518,28 @@ function common_shorten_url($long_url)
curl_close($curlh);
return $short_url;
-} \ No newline at end of file
+}
+
+function common_client_ip()
+{
+ if (!isset($_SERVER) || !array_key_exists('REQUEST_METHOD', $_SERVER)) {
+ return null;
+ }
+
+ if ($_SERVER['HTTP_X_FORWARDED_FOR']) {
+ if ($_SERVER['HTTP_CLIENT_IP']) {
+ $proxy = $_SERVER['HTTP_CLIENT_IP'];
+ } else {
+ $proxy = $_SERVER['REMOTE_ADDR'];
+ }
+ $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
+ } else {
+ if ($_SERVER['HTTP_CLIENT_IP']) {
+ $ip = $_SERVER['HTTP_CLIENT_IP'];
+ } else {
+ $ip = $_SERVER['REMOTE_ADDR'];
+ }
+ }
+
+ return array($ip, $proxy);
+}
diff --git a/scripts/commandline.inc b/scripts/commandline.inc
index 4a7757fb9..3b6ef6098 100644
--- a/scripts/commandline.inc
+++ b/scripts/commandline.inc
@@ -63,14 +63,21 @@ if (isset($longoptions)) {
$parser = new Console_Getopt();
-list($options, $args) = $parser->getopt($argv, $shortoptions, $longoptions);
+$result = $parser->getopt($argv, $shortoptions, $longoptions);
+
+if (PEAR::isError($result)) {
+ print $result->getMessage()."\n";
+ exit(1);
+} else {
+ list($options, $args) = $result;
+}
function show_help()
{
global $helptext;
$_default_help_text = <<<END_OF_DEFAULT
-General options:
+ General options:
-q --quiet Quiet (little output)
-v --verbose Verbose (lots of output)
@@ -80,11 +87,11 @@ General options:
-h --help Show this message and quit.
END_OF_DEFAULT;
- if (isset($helptext)) {
- print $helptext;
- }
- print $_default_help_text;
- exit(0);
+ if (isset($helptext)) {
+ print $helptext;
+ }
+ print $_default_help_text;
+ exit(0);
}
foreach ($options as $option) {
@@ -115,24 +122,53 @@ require_once INSTALLDIR . '/lib/common.php';
set_error_handler('common_error_handler');
-function have_option($str)
+function _make_matches($opt, $alt)
{
- global $options;
- foreach ($options as $option) {
- if ($option[0] == $str) {
- return true;
- }
- }
- return false;
+ $matches = array();
+
+ if (strlen($opt) > 1 && 0 != strncmp($opt, '--', 2)) {
+ $matches[] = '--'.$opt;
+ } else {
+ $matches[] = $opt;
+ }
+
+ if (!empty($alt)) {
+ if (strlen($alt) > 1 && 0 != strncmp($alt, '--', 2)) {
+ $matches[] = '--'.$alt;
+ } else {
+ $matches[] = $alt;
+ }
+ }
+
+ return $matches;
}
-function get_option_value($str)
+function have_option($opt, $alt=null)
{
- global $options;
- foreach ($options as $option) {
- if ($option[0] == $str) {
- return $option[1];
- }
- }
- return null;
-} \ No newline at end of file
+ global $options;
+
+ $matches = _make_matches($opt, $alt);
+
+ foreach ($options as $option) {
+ if (in_array($option[0], $matches)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function get_option_value($opt, $alt=null)
+{
+ global $options;
+
+ $matches = _make_matches($opt, $alt);
+
+ foreach ($options as $option) {
+ if (in_array($option[0], $matches)) {
+ return $option[1];
+ }
+ }
+
+ return null;
+}
diff --git a/scripts/fixup_conversations.php b/scripts/fixup_conversations.php
index 2cfa422e6..0be0b4bac 100755
--- a/scripts/fixup_conversations.php
+++ b/scripts/fixup_conversations.php
@@ -24,22 +24,17 @@ require_once INSTALLDIR.'/scripts/commandline.inc';
common_log(LOG_INFO, 'Fixing up conversations.');
-$notice = new Notice();
-$notice->whereAdd('conversation is null');
-$notice->orderBy('id');
+$nid = new Notice();
+$nid->query('select id, reply_to from notice where conversation is null');
-$cnt = $notice->find();
+while ($nid->fetch()) {
-print "Found $cnt notices.\n";
-
-while ($notice->fetch()) {
-
- print "$notice->id =>";
-
- $orig = clone($notice);
-
- if (empty($notice->reply_to)) {
- $notice->conversation = $notice->id;
+ $cid = null;
+
+ $notice = new Notice();
+
+ if (empty($nid->reply_to)) {
+ $cid = $nid->id;
} else {
$reply = Notice::staticGet('id', $notice->reply_to);
@@ -52,6 +47,9 @@ while ($notice->fetch()) {
} else {
$notice->conversation = $reply->conversation;
}
+
+ unset($reply);
+ $reply = null;
}
print "$notice->conversation";
@@ -63,5 +61,10 @@ while ($notice->fetch()) {
continue;
}
+ $notice = null;
+ $orig = null;
+ unset($notice);
+ unset($orig);
+
print ".\n";
}
diff --git a/scripts/twitterstatusfetcher.php b/scripts/twitterstatusfetcher.php
index 5ffdda58f..8b10bfbad 100755
--- a/scripts/twitterstatusfetcher.php
+++ b/scripts/twitterstatusfetcher.php
@@ -25,9 +25,14 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('MAXCHILDREN', 2);
define('POLL_INTERVAL', 60); // in seconds
+$shortoptions = 'i::';
+$longoptions = array('id::');
+
$helptext = <<<END_OF_TRIM_HELP
Batch script for retrieving Twitter messages from foreign service.
+ -i --id Identity (default 'generic')
+
END_OF_TRIM_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
@@ -64,7 +69,7 @@ class TwitterStatusFetcher extends Daemon
function name()
{
- return ('twitterstatusfetcher.generic');
+ return ('twitterstatusfetcher.'.$this->_id);
}
/**
@@ -625,6 +630,16 @@ class TwitterStatusFetcher extends Daemon
declare(ticks = 1);
-$fetcher = new TwitterStatusFetcher();
+if (have_option('i')) {
+ $id = get_option_value('i');
+} else if (have_option('--id')) {
+ $id = get_option_value('--id');
+} else if (count($args) > 0) {
+ $id = $args[0];
+} else {
+ $id = null;
+}
+
+$fetcher = new TwitterStatusFetcher($id);
$fetcher->runOnce();
diff --git a/scripts/xmppdaemon.php b/scripts/xmppdaemon.php
index 3eecfec29..ca6218120 100755
--- a/scripts/xmppdaemon.php
+++ b/scripts/xmppdaemon.php
@@ -20,13 +20,14 @@
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-$shortoptions = 'i::';
-$longoptions = array('id::');
+$shortoptions = 'fi::';
+$longoptions = array('id::', 'foreground');
$helptext = <<<END_OF_XMPP_HELP
Daemon script for receiving new notices from Jabber users.
-i --id Identity (default none)
+ -f --foreground Stay in the foreground (default background)
END_OF_XMPP_HELP;
@@ -42,8 +43,10 @@ require_once INSTALLDIR . '/lib/daemon.php';
class XMPPDaemon extends Daemon
{
- function XMPPDaemon($resource=null)
+ function __construct($resource=null, $daemonize=true)
{
+ parent::__construct($daemonize);
+
static $attrs = array('server', 'port', 'user', 'password', 'host');
foreach ($attrs as $attr)
@@ -62,7 +65,6 @@ class XMPPDaemon extends Daemon
function connect()
{
-
$connect_to = ($this->host) ? $this->host : $this->server;
$this->log(LOG_INFO, "Connecting to $connect_to on port $this->port");
@@ -73,10 +75,17 @@ class XMPPDaemon extends Daemon
return false;
}
+ $this->log(LOG_INFO, "Connected");
+
$this->conn->setReconnectTimeout(600);
+ $this->log(LOG_INFO, "Sending initial presence.");
+
jabber_send_presence("Send me a message to post a notice", 'available',
null, 'available', 100);
+
+ $this->log(LOG_INFO, "Done connecting.");
+
return !$this->conn->isDisconnected();
}
@@ -89,17 +98,23 @@ class XMPPDaemon extends Daemon
{
if ($this->connect()) {
+ $this->log(LOG_DEBUG, "Initializing stanza handlers.");
+
$this->conn->addEventHandler('message', 'handle_message', $this);
$this->conn->addEventHandler('presence', 'handle_presence', $this);
$this->conn->addEventHandler('reconnect', 'handle_reconnect', $this);
+ $this->log(LOG_DEBUG, "Beginning processing loop.");
+
$this->conn->process();
}
}
function handle_reconnect(&$pl)
{
+ $this->log(LOG_DEBUG, "Got reconnection callback.");
$this->conn->processUntil('session_start');
+ $this->log(LOG_DEBUG, "Sending reconnection presence.");
$this->conn->presence('Send me a message to post a notice', 'available', null, 'available', 100);
}
@@ -111,21 +126,27 @@ class XMPPDaemon extends Daemon
function handle_message(&$pl)
{
+ $from = jabber_normalize_jid($pl['from']);
+
if ($pl['type'] != 'chat') {
+ $this->log(LOG_WARNING, "Ignoring message of type ".$pl['type']." from $from.");
return;
}
+
if (mb_strlen($pl['body']) == 0) {
+ $this->log(LOG_WARNING, "Ignoring message with empty body from $from.");
return;
}
- $from = jabber_normalize_jid($pl['from']);
-
# Forwarded from another daemon (probably a broadcaster) for
# us to handle
if ($this->is_self($from)) {
+ $this->log(LOG_INFO, "Got forwarded notice from self ($from).");
$from = $this->get_ofrom($pl);
+ $this->log(LOG_INFO, "Originally sent by $from.");
if (is_null($from) || $this->is_self($from)) {
+ $this->log(LOG_INFO, "Ignoring notice originally sent by $from.");
return;
}
}
@@ -140,6 +161,7 @@ class XMPPDaemon extends Daemon
return;
}
if ($this->handle_command($user, $pl['body'])) {
+ $this->log(LOG_INFO, "Command messag by $from handled.");
return;
} else if ($this->is_autoreply($pl['body'])) {
$this->log(LOG_INFO, 'Ignoring auto reply from ' . $from);
@@ -148,12 +170,20 @@ class XMPPDaemon extends Daemon
$this->log(LOG_INFO, 'Ignoring OTR from ' . $from);
return;
} else if ($this->is_direct($pl['body'])) {
+ $this->log(LOG_INFO, 'Got a direct message ' . $from);
+
preg_match_all('/d[\ ]*([a-z0-9]{1,64})/', $pl['body'], $to);
$to = preg_replace('/^d([\ ])*/', '', $to[0][0]);
$body = preg_replace('/d[\ ]*('. $to .')[\ ]*/', '', $pl['body']);
+
+ $this->log(LOG_INFO, 'Direct message from '. $user->nickname . ' to ' . $to);
+
$this->add_direct($user, $body, $to, $from);
} else {
+
+ $this->log(LOG_INFO, 'Posting a notice from ' . $user->nickname);
+
$this->add_notice($user, $pl);
}
@@ -261,6 +291,7 @@ class XMPPDaemon extends Daemon
$notice = Notice::saveNew($user->id, $content_shortened, 'xmpp');
if (is_string($notice)) {
$this->log(LOG_ERR, $notice);
+ $this->from_site($user->jabber, $notice);
return;
}
common_broadcast_notice($notice);
@@ -307,7 +338,14 @@ class XMPPDaemon extends Daemon
function log($level, $msg)
{
- common_log($level, 'XMPPDaemon('.$this->resource.'): '.$msg);
+ $text = 'XMPPDaemon('.$this->resource.'): '.$msg;
+ common_log($level, $text);
+ if (!$this->daemonize)
+ {
+ $line = common_log_line($level, $text);
+ echo $line;
+ echo "\n";
+ }
}
function subscribed($to)
@@ -323,16 +361,16 @@ if (common_config('xmpp','enabled')==false) {
exit();
}
-if (have_option('i')) {
- $id = get_option_value('i');
-} else if (have_option('--id')) {
- $id = get_option_value('--id');
+if (have_option('i', 'id')) {
+ $id = get_option_value('i', 'id');
} else if (count($args) > 0) {
$id = $args[0];
} else {
$id = null;
}
-$daemon = new XMPPDaemon($id);
+$foreground = have_option('f', 'foreground');
+
+$daemon = new XMPPDaemon($id, !$foreground);
$daemon->runOnce();
diff --git a/theme/base/css/display.css b/theme/base/css/display.css
index 85b42cdd1..eb9c4652f 100644
--- a/theme/base/css/display.css
+++ b/theme/base/css/display.css
@@ -273,7 +273,6 @@ clear:both;
margin-bottom:18px;
}
-
#anon_notice {
float:left;
width:43.2%;
@@ -288,7 +287,6 @@ font-size:1.1em;
font-weight:bold;
}
-
#footer {
float:left;
width:64%;
@@ -600,7 +598,6 @@ display:none;
}
/* entity_profile */
-
/*entity_actions*/
.entity_actions {
float:right;
@@ -729,7 +726,6 @@ margin-bottom:0;
min-height:60px;
}
-
.profile .form_group_join legend,
.profile .form_group_leave legend,
.profile .form_user_subscribe legend,
@@ -764,13 +760,11 @@ display:inline;
margin-right:11px;
}
-
.profile .entity_profile .form_subscription_edit label {
font-weight:normal;
margin-right:11px;
}
-
/* NOTICE */
.notice,
.profile {
@@ -793,7 +787,6 @@ width:95%;
float:left;
}
-
/* NOTICES */
#notices_primary {
float:left;
@@ -965,7 +958,6 @@ border:0;
padding:0;
}
-
.notice .attachment {
position:relative;
padding-left:16px;
@@ -1062,7 +1054,6 @@ margin-bottom:18px;
padding-left:20px;
}
-
#filter_tags {
margin-bottom:11px;
float:left;
@@ -1108,8 +1099,6 @@ top:3px;
left:3px;
}
-
-
.pagination {
float:left;
clear:both;
@@ -1155,7 +1144,6 @@ padding-right:30px;
}
/* END: NOTICE */
-
.hentry .entry-content p {
margin-bottom:18px;
}
@@ -1172,7 +1160,6 @@ margin-bottom:18px;
margin-left:18px;
}
-
/* TOP_POSTERS */
.section tbody td {
padding-right:18px;
@@ -1200,7 +1187,6 @@ margin-right:0;
display:none;
}
-
/* tagcloud */
.tag-cloud {
list-style-type:none;
@@ -1317,3 +1303,6 @@ display:none;
.guide {
clear:both;
}
+.admin_indicator {
+font-style:italic;
+} \ No newline at end of file