]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge commit 'jeff-themovie/small-fixes' into 0.8.x
authorZach Copley <zach@controlyourself.ca>
Tue, 30 Jun 2009 23:25:52 +0000 (16:25 -0700)
committerZach Copley <zach@controlyourself.ca>
Tue, 30 Jun 2009 23:25:52 +0000 (16:25 -0700)
* commit 'jeff-themovie/small-fixes':
  Fix missing max_id in API search calls
  Fix "Trying to get property of non-object" errors when a user tries to log in using an unknown nickname
  Fix "Trying to get property of non-object" errors when accessing the people search results page
  Fix "Undefined variable: cnt"
  Fix "Trying to get property of non-object" errors in groupeditform.php
  Fix "Undefined property: DisfavorAction::$id"

51 files changed:
README
actions/api.php
actions/attachment.php
actions/conversation.php
actions/file.php
actions/groupdesignsettings.php
actions/groupmembers.php
actions/grouprss.php
actions/invite.php
actions/newnotice.php
actions/noticesearchrss.php
actions/public.php
actions/showgroup.php
actions/sup.php
actions/twitapisearchatom.php
actions/twitapisearchjson.php
actions/userdesignsettings.php
classes/Design.php
classes/Notice.php
classes/Session.php [new file with mode: 0644]
classes/Status_network.php
classes/User_group.php
classes/laconica.ini [changed mode: 0755->0644]
config.php.sample
db/laconica.sql
extlib/Mail/mimeDecode.php [new file with mode: 0644]
extlib/XMPPHP/BOSH.php
extlib/XMPPHP/XMLStream.php
extlib/XMPPHP/XMPP.php
index.php
install.php
js/jquery.joverlay.min.js
js/userdesign.go.js
js/util.js
lib/action.php
lib/common.php
lib/daemon.php
lib/designsettings.php
lib/facebookaction.php
lib/language.php
lib/queuehandler.php
lib/router.php
lib/subgroupnav.php
lib/util.php
plugins/FBConnect/FBConnectPlugin.php
scripts/commandline.inc
scripts/fixup_conversations.php
scripts/showcache.php [new file with mode: 0644]
scripts/twitterstatusfetcher.php
scripts/xmppdaemon.php
theme/base/css/display.css

diff --git a/README b/README
index 1a57d6a80e53d6ed09e78862f26e52893b0a8c04..e02fa02d31bc42e21ab9296f701df4c29cce8b43 100644 (file)
--- a/README
+++ b/README
@@ -1081,6 +1081,13 @@ debug: if turned on, this will make the XMPP library blurt out all of
 public: an array of JIDs to send _all_ notices to. This is useful for
        participating in third-party search and archiving services.
 
+invite
+------
+
+For configuring invites.
+
+enabled: Whether to allow users to send invites. Default true.
+
 tag
 ---
 
@@ -1278,6 +1285,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
 ===============
 
index 1fe5875ad6b586d6ec2fe7f2938ceab0110797dd..08f5fadad99d70c657fa07a97e6cd972c7a1fc0d 100644 (file)
@@ -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();
                 }
             }
index e4dc0e054e27be9a238ad842eb823a8575e8d989..ee4cd9640d971d1b0b19bbe1cdbfa6b1ee5be67b 100644 (file)
@@ -111,7 +111,16 @@ class AttachmentAction extends Action
     function handle($args)
     {
         parent::handle($args);
-        $this->showPage();
+
+        if (empty($this->attachment->filename)) {
+
+            // if it's not a local file, gtfo
+
+            common_redirect($this->attachment->url, 303);
+
+        } else {
+            $this->showPage();
+        }
     }
 
     /**
index 654a670f54ca6113ddcc31ad34503c29cfdf1791..79197da2d0a8484c0dcffebba673bae4b9acd0d0 100644 (file)
@@ -107,17 +107,11 @@ class ConversationAction extends Action
 
     function showContent()
     {
-        $offset = ($this->page-1) * NOTICES_PER_PAGE;
-        $limit  = NOTICES_PER_PAGE + 1;
-
-        $notices = Notice::conversationStream($this->id, $offset, $limit);
+        $notices = Notice::conversationStream($this->id);
 
         $ct = new ConversationTree($notices, $this);
 
         $cnt = $ct->show();
-
-        $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
-                          $this->page, 'conversation', array('id' => $this->id));
     }
 }
 
@@ -148,6 +142,25 @@ class ConversationTree extends NoticeList
     {
         $cnt = 0;
 
+        $this->_buildTree();
+
+        $this->out->elementStart('div', array('id' =>'notices_primary'));
+        $this->out->element('h2', null, _('Notices'));
+        $this->out->elementStart('ol', array('class' => 'notices xoxo'));
+
+        if (array_key_exists('root', $this->tree)) {
+            $rootid = $this->tree['root'][0];
+            $this->showNoticePlus($rootid);
+        }
+
+        $this->out->elementEnd('ol');
+        $this->out->elementEnd('div');
+
+        return $cnt;
+    }
+
+    function _buildTree()
+    {
         $this->tree  = array();
         $this->table = array();
 
@@ -168,20 +181,6 @@ class ConversationTree extends NoticeList
                 $this->tree[$notice->reply_to] = array($notice->id);
             }
         }
-
-        $this->out->elementStart('div', array('id' =>'notices_primary'));
-        $this->out->element('h2', null, _('Notices'));
-        $this->out->elementStart('ol', array('class' => 'notices xoxo'));
-
-        if (array_key_exists('root', $this->tree)) {
-            $rootid = $this->tree['root'][0];
-            $this->showNoticePlus($rootid);
-        }
-
-        $this->out->elementEnd('ol');
-        $this->out->elementEnd('div');
-
-        return $cnt;
     }
 
     /**
index 271f57ab9634aeaa4a6d675d30ac46a2849f30c8..8310e48df1565431f1ba23f5a4455af455c73c1c 100644 (file)
@@ -56,5 +56,17 @@ class FileAction extends Action
     function handle() {
         common_redirect($this->filerec->url);
     }
+
+    /**
+     * Is this action read-only?
+     *
+     * @return boolean true
+     */
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
 }
 
index 79c192ac466bceeb9b0988a67ade4a9ae2ab7aad..6c1c052cba10b130abeea09b54d283acb1539149 100644 (file)
@@ -34,19 +34,37 @@ if (!defined('LACONICA')) {
 
 require_once INSTALLDIR . '/lib/designsettings.php';
 
+/**
+ * Set a group's design
+ *
+ * Saves a design for a given group
+ *
+ * @category Settings
+ * @package  Laconica
+ * @author   Zach Copley <zach@controlyourself.ca>
+ * @author   Sarven Capadisli <csarven@controlyourself.ca>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://laconi.ca/
+ */
+
 class GroupDesignSettingsAction extends DesignSettingsAction
 {
     var $group = null;
 
     /**
-     * Prepare to run
+     * Sets the right action for the form, and passes request args into
+     * the base action
+     *
+     * @param array $args misc. arguments
+     *
+     * @return boolean true
      */
 
     function prepare($args)
     {
         parent::prepare($args);
 
-        if (!common_config('inboxes','enabled')) {
+        if (!common_config('inboxes', 'enabled')) {
             $this->serverError(_('Inboxes must be enabled for groups to work'));
             return false;
         }
@@ -57,7 +75,7 @@ class GroupDesignSettingsAction extends DesignSettingsAction
         }
 
         $nickname_arg = $this->trimmed('nickname');
-        $nickname = common_canonical_nickname($nickname_arg);
+        $nickname     = common_canonical_nickname($nickname_arg);
 
         // Permanent redirect on non-canonical nickname
 
@@ -158,7 +176,8 @@ class GroupDesignSettingsAction extends DesignSettingsAction
      * @return Design
      */
 
-    function getWorkingDesign() {
+    function getWorkingDesign()
+    {
 
         $design = null;
 
@@ -273,9 +292,9 @@ class GroupDesignSettingsAction extends DesignSettingsAction
                 return;
             }
 
-            $original = clone($this->group);
+            $original               = clone($this->group);
             $this->group->design_id = $id;
-            $result = $this->group->update($original);
+            $result                 = $this->group->update($original);
 
             if (empty($result)) {
                 common_log_db_error($original, 'UPDATE', __FILE__);
index d132cdf9670512d5f5083a713726af77b014d90b..14256526a059453bf887ab819fbedf00cf511b48 100644 (file)
@@ -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', 'role', _('Admin'));
+        }
+    }
+
     function showActions()
     {
         $this->startActions();
index 0b7280a11c33648584096b95176eafb63fea7835..2bdcaafb27a56e17ea1bd556741e34ba70880599 100644 (file)
@@ -116,6 +116,7 @@ class groupRssAction extends Rss10Action
             return null;
         }
 
+        $notices = array();
         $notice = $group->getNotices(0, ($limit == 0) ? NOTICES_PER_PAGE : $limit);
 
         while ($notice->fetch()) {
index 5dcc836526317e7b124dd4c03ea2bca6606cdb2f..bdea4807d8a2f2ac0f7f8c1043d35c6d56d6595d 100644 (file)
@@ -35,7 +35,9 @@ class InviteAction extends CurrentUserDesignAction
     function handle($args)
     {
         parent::handle($args);
-        if (!common_logged_in()) {
+        if (!common_config('invite', 'enabled')) {
+            $this->clientError(_('Invites have been disabled.'));
+        } else if (!common_logged_in()) {
             $this->clientError(sprintf(_('You must be logged in to invite other users to use %s'),
                                         common_config('site', 'name')));
             return;
index 15caff6eaab0042783314c8cc1e6d80e7f9977cc..5f44a32a96a5601a2582a9dbdb66f39b3f27e6d0 100644 (file)
@@ -229,14 +229,25 @@ class NewnoticeAction extends Action
             if (empty($filename)) {
                 $this->clientError(_('Couldn\'t save file.'));
             }
-            $fileurl = File::url($filename);
+
+            $fileRecord = $this->storeFile($filename, $mimetype);
+
+            $fileurl = common_local_url('attachment',
+                array('attachment' => $fileRecord->id));
+
+            // not sure this is necessary -- Zach
+            $this->maybeAddRedir($fileRecord->id, $fileurl);
+
             $short_fileurl = common_shorten_url($fileurl);
             $content_shortened .= ' ' . $short_fileurl;
+
             if (mb_strlen($content_shortened) > 140) {
                 $this->deleteFile($filename);
                 $this->clientError(_('Max notice size is 140 chars, including attachment URL.'));
             }
-            $fileRecord = $this->rememberFile($filename, $mimetype, $short_fileurl);
+
+            // Also, not sure this is necessary -- Zach
+            $this->maybeAddRedir($fileRecord->id, $short_fileurl);
         }
 
         $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
@@ -305,8 +316,8 @@ class NewnoticeAction extends Action
         @unlink($filepath);
     }
 
-    function rememberFile($filename, $mimetype, $short)
-    {
+    function storeFile($filename, $mimetype) {
+
         $file = new File;
         $file->filename = $filename;
 
@@ -325,11 +336,14 @@ class NewnoticeAction extends Action
             $this->clientError(_('There was a database error while saving your file. Please try again.'));
         }
 
-        $this->maybeAddRedir($file_id, $short);
-
         return $file;
     }
 
+    function rememberFile($file, $short)
+    {
+        $this->maybeAddRedir($file->id, $short);
+    }
+
     function maybeAddRedir($file_id, $url)
     {
         $file_redir = File_redirection::staticGet('url', $url);
index c1bf3bf5f21db9311e3b9b60b6b170c592f50a9d..2a4b2060d3fa3f2d3781d429f27cbd5a372ce9a3 100644 (file)
@@ -67,11 +67,16 @@ class NoticesearchrssAction extends Rss10Action
 
         if (!$limit) $limit = 20;
         $search_engine->limit(0, $limit, true);
-        $search_engine->query($q);
-        $notice->find();
+        if (false === $search_engine->query($q)) {
+            $cnt = 0;
+        } else {
+            $cnt = $notice->find();
+        }
 
-        while ($notice->fetch()) {
-            $notices[] = clone($notice);
+        if ($cnt > 0) {
+            while ($notice->fetch()) {
+                $notices[] = clone($notice);
+            }
         }
 
         return $notices;
index 9851285c4821367288b1bd8c5797d3a4912ca840..ef9ef0d1ab0dc4ea451d29f1c1a016359533501c 100644 (file)
@@ -182,8 +182,10 @@ class PublicAction extends Action
             $message .= _('Be the first to post!');
         }
         else {
-            $message .= _('Why not [register an account](%%action.register%%) and be the first to post!');
-        }
+            if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
+                $message .= _('Why not [register an account](%%action.register%%) and be the first to post!');
+            }
+       }
 
         $this->elementStart('div', 'guide');
         $this->raw(common_markup_to_html($message));
index b6a0f4844e78a69752cd6c690203b54d869ede07..ce11d574e94c7be3577902b15d5ef51590fa94f7 100644 (file)
@@ -331,6 +331,7 @@ class ShowgroupAction extends GroupDesignAction
     {
         $this->showMembers();
         $this->showStatistics();
+        $this->showAdmins();
         $cloud = new GroupTagCloudSection($this, $this->group);
         $cloud->show();
     }
@@ -369,6 +370,18 @@ class ShowgroupAction extends GroupDesignAction
         $this->elementEnd('div');
     }
 
+    /**
+     * Show list of admins
+     *
+     * @return void
+     */
+
+    function showAdmins()
+    {
+        $adminSection = new GroupAdminSection($this, $this->group);
+        $adminSection->show();
+    }
+
     /**
      * Show some statistics
      *
@@ -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
index e446a7b0ddfc3ba0723e8c4eeb0622fcf4418d2a..a5b665562f31f6c3a0624581583e8bade61e3e29 100644 (file)
@@ -63,11 +63,13 @@ class SupAction extends Action
         # XXX: cache this. Depends on how big this protocol becomes;
         # Re-doing this query every 15 seconds isn't the end of the world.
 
+        $divider = common_sql_date(time() - $seconds);
+
         $notice->query('SELECT profile_id, max(id) AS max_id ' .
                        'FROM notice ' .
                         ((common_config('db','type') == 'pgsql') ?
                        'WHERE extract(epoch from created) > (extract(epoch from now()) - ' . $seconds . ') ' :
-                       'WHERE created > (now() - ' . $seconds . ') ' ) .
+                       'WHERE created > "'.$divider.'" ' ) .
                        'GROUP BY profile_id');
 
         $updates = array();
index c223a7e27c19e4a196508caa27350b93b666b0c8..3678213c3a9dbddd34050b9a4936b3f49d6a573f 100644 (file)
@@ -165,25 +165,30 @@ class TwitapisearchatomAction extends TwitterapiAction
         $search_engine->set_sort_mode('chron');
         $search_engine->limit(($this->page - 1) * $this->rpp,
             $this->rpp + 1, true);
-        $search_engine->query($q);
-        $this->cnt = $notice->find();
+        if (false === $search_engine->query($q)) {
+            $this->cnt = 0;
+        } else {
+            $this->cnt = $notice->find();
+        }
 
         $cnt = 0;
         $this->max_id = 0;
 
-        while ($notice->fetch()) {
+        if ($this->cnt > 0) {
+            while ($notice->fetch()) {
 
-            ++$cnt;
+                ++$cnt;
 
-            if (!$this->max_id) {
-                $this->max_id = $notice->id;
-            }
+                if (!$this->max_id) {
+                    $this->max_id = $notice->id;
+                }
 
-            if ($cnt > $this->rpp) {
-                break;
-            }
+                if ($cnt > $this->rpp) {
+                    break;
+                }
 
-            $notices[] = clone($notice);
+                $notices[] = clone($notice);
+            }
         }
 
         return $notices;
index b0e3be687c1118da16e0f88584911b6a7b786c2e..27a717bfc988cc0bc7b2ef40a8fa24739a032ced 100644 (file)
@@ -124,8 +124,11 @@ class TwitapisearchjsonAction extends TwitterapiAction
         $search_engine = $notice->getSearchEngine('identica_notices');
         $search_engine->set_sort_mode('chron');
         $search_engine->limit(($this->page - 1) * $this->rpp, $this->rpp + 1, true);
-        $search_engine->query($q);
-        $cnt = $notice->find();
+        if (false === $search_engine->query($q)) {
+            $cnt = 0;
+        } else {
+            $cnt = $notice->find();
+        }
 
         // TODO: since_id, lang, geocode
 
@@ -146,4 +149,4 @@ class TwitapisearchjsonAction extends TwitterapiAction
     {
         return true;
     }
-}
\ No newline at end of file
+}
index 6e745e96f8dd9614da4743822a95bf1937062500..d7949951abaae210dcd2a3a925d5b6aa5d975e05 100644 (file)
@@ -34,16 +34,37 @@ if (!defined('LACONICA')) {
 
 require_once INSTALLDIR . '/lib/designsettings.php';
 
+/**
+ * Set a user's design
+ *
+ * Saves a design for a given user
+ *
+ * @category Settings
+ * @package  Laconica
+ * @author   Zach Copley <zach@controlyourself.ca>
+ * @author   Sarven Capadisli <csarven@controlyourself.ca>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://laconi.ca/
+ */
+
 class UserDesignSettingsAction extends DesignSettingsAction
 {
+    /**
+     * Sets the right action for the form, and passes request args into
+     * the base action
+     *
+     * @param array $args misc. arguments
+     *
+     * @return boolean true
+     */
+
     function prepare($args)
     {
         parent::prepare($args);
         $this->submitaction = common_local_url('userdesignsettings');
         return true;
     }
-     
+
     /**
      * Title of the page
      *
@@ -72,19 +93,20 @@ class UserDesignSettingsAction extends DesignSettingsAction
      *
      * @return Design
      */
-     
-    function getWorkingDesign() {
-        
-        $user = common_current_user();
+
+    function getWorkingDesign()
+    {
+
+        $user   = common_current_user();
         $design = $user->getDesign();
 
         if (empty($design)) {
             $design = $this->defaultDesign();
         }
-     
+
         return $design;
     }
-    
+
     /**
      * Content area of the page
      *
@@ -92,7 +114,7 @@ class UserDesignSettingsAction extends DesignSettingsAction
      *
      * @return void
      */
-     
+
     function showContent()
     {
         $this->showDesignForm($this->getWorkingDesign());
@@ -106,14 +128,19 @@ class UserDesignSettingsAction extends DesignSettingsAction
 
     function saveDesign()
     {
-        try {
+        foreach ($this->args as $key => $val) {
+            if (preg_match('/(#ho|ho)Td.*g/i', $val)) {
+                $this->sethd();
+                return;
+            }
+        }
 
+        try {
             $bgcolor = new WebColor($this->trimmed('design_background'));
             $ccolor  = new WebColor($this->trimmed('design_content'));
             $sbcolor = new WebColor($this->trimmed('design_sidebar'));
             $tcolor  = new WebColor($this->trimmed('design_text'));
             $lcolor  = new WebColor($this->trimmed('design_links'));
-
         } catch (WebColorException $e) {
             $this->showForm($e->getMessage());
             return;
@@ -137,7 +164,7 @@ class UserDesignSettingsAction extends DesignSettingsAction
             $tile = true;
         }
 
-        $user = common_current_user();
+        $user   = common_current_user();
         $design = $user->getDesign();
 
         if (!empty($design)) {
@@ -184,9 +211,9 @@ class UserDesignSettingsAction extends DesignSettingsAction
                 return;
             }
 
-            $original = clone($user);
+            $original        = clone($user);
             $user->design_id = $id;
-            $result = $user->update($original);
+            $result          = $user->update($original);
 
             if (empty($result)) {
                 common_log_db_error($original, 'UPDATE', __FILE__);
@@ -203,4 +230,56 @@ class UserDesignSettingsAction extends DesignSettingsAction
 
         $this->showForm(_('Design preferences saved.'), true);
     }
+
+    /**
+     * Alternate default colors
+     *
+     * @return nothing
+     */
+
+    function sethd()
+    {
+
+        $user   = common_current_user();
+        $design = $user->getDesign();
+
+        $user->query('BEGIN');
+
+        // alternate colors
+        $design = new Design();
+
+        $design->backgroundcolor = 16184329;
+        $design->contentcolor    = 16059904;
+        $design->sidebarcolor    = 16059904;
+        $design->textcolor       = 0;
+        $design->linkcolor       = 16777215;
+
+        $design->setDisposition(false, true, false);
+
+        $id = $design->insert();
+
+        if (empty($id)) {
+            common_log_db_error($id, 'INSERT', __FILE__);
+            $this->showForm(_('Unable to save your design settings!'));
+            return;
+        }
+
+        $original        = clone($user);
+        $user->design_id = $id;
+        $result          = $user->update($original);
+
+        if (empty($result)) {
+            common_log_db_error($original, 'UPDATE', __FILE__);
+            $this->showForm(_('Unable to save your design settings!'));
+            $user->query('ROLLBACK');
+            return;
+        }
+
+        $user->query('COMMIT');
+
+        $this->saveBackgroundImage($design);
+
+        $this->showForm(_('Enjoy your hotdog!'), true);
+    }
+
 }
index da4b670be06c41440711f1df486e7521be0f44fd..0927fcda70e729ef70e6fa8c8132d38882a8dba2 100644 (file)
@@ -85,7 +85,7 @@ class Design extends Memcached_DataObject
 
             $css .= 'body { background-image:url(' .
                 Design::url($this->backgroundimage) .
-                '); ' . $repeat . ' }' . "\n";
+                '); ' . $repeat . ' background-attachment:fixed; }' . "\n";
         }
 
         $out->element('style', array('type' => 'text/css'), $css);
index fdcef1bc2ed6de3e17a82e505abe90b2aeb5eebf..2ba2f31b1a62f47202f45caece88121b9f0a14e3 100644 (file)
@@ -34,6 +34,8 @@ define('NOTICE_REMOTE_OMB', 0);
 define('NOTICE_LOCAL_NONPUBLIC', -1);
 define('NOTICE_GATEWAY', -2);
 
+define('MAX_BOXCARS', 128);
+
 class Notice extends Memcached_DataObject
 {
     ###START_AUTOCODE
@@ -221,7 +223,7 @@ class Notice extends Memcached_DataObject
             $notice->saveTags();
 
             $notice->addToInboxes();
-            $notice->saveGroups();
+
             $notice->saveUrls();
             $orig2 = clone($notice);
                $notice->rendered = common_render_content($final, $notice);
@@ -793,7 +795,7 @@ class Notice extends Memcached_DataObject
         $notice->selectAdd(); // clears it
         $notice->selectAdd('id');
 
-        $notice->whereAdd('conversation = '.$id);
+        $notice->conversation = $id;
 
         $notice->orderBy('id DESC');
 
@@ -833,14 +835,55 @@ class Notice extends Memcached_DataObject
 
         if ($enabled === true || $enabled === 'transitional') {
 
+            // XXX: loads constants
+
+            $inbox = new Notice_inbox();
+
             $users = $this->getSubscribedUsers();
 
             // FIXME: kind of ignoring 'transitional'...
             // we'll probably stop supporting inboxless mode
             // in 0.9.x
 
+            $ni = array();
+
             foreach ($users as $id) {
-                $this->addToUserInbox($id, NOTICE_INBOX_SOURCE_SUB);
+                $ni[$id] = NOTICE_INBOX_SOURCE_SUB;
+            }
+
+            $groups = $this->saveGroups();
+
+            foreach ($groups as $group) {
+                $users = $group->getUserMembers();
+                foreach ($users as $id) {
+                    if (!array_key_exists($id, $ni)) {
+                        $ni[$id] = NOTICE_INBOX_SOURCE_GROUP;
+                    }
+                }
+            }
+
+            $cnt = 0;
+
+            $qryhdr = 'INSERT INTO notice_inbox (user_id, notice_id, source, created) VALUES ';
+            $qry = $qryhdr;
+
+            foreach ($ni as $id => $source) {
+                if ($cnt > 0) {
+                    $qry .= ', ';
+                }
+                $qry .= '('.$id.', '.$this->id.', '.$source.', "'.$this->created.'") ';
+                $cnt++;
+                if ($cnt >= MAX_BOXCARS) {
+                    $inbox = new Notice_inbox();
+                    $inbox->query($qry);
+                    $qry = $qryhdr;
+                    $cnt = 0;
+                }
+            }
+
+            if ($cnt > 0) {
+                $inbox = new Notice_inbox();
+                $inbox->query($qry);
             }
         }
 
@@ -870,27 +913,13 @@ class Notice extends Memcached_DataObject
         return $ids;
     }
 
-    function addToUserInbox($user_id, $source)
-    {
-        $inbox = Notice_inbox::pkeyGet(array('user_id' => $user_id,
-                                             'notice_id' => $this->id));
-        if (empty($inbox)) {
-            $inbox = new Notice_inbox();
-            $inbox->user_id   = $user_id;
-            $inbox->notice_id = $this->id;
-            $inbox->source    = $source;
-            $inbox->created   = $this->created;
-            return $inbox->insert();
-        }
-
-        return true;
-    }
-
     function saveGroups()
     {
+        $groups = array();
+
         $enabled = common_config('inboxes', 'enabled');
         if ($enabled !== true && $enabled !== 'transitional') {
-            return;
+            return $groups;
         }
 
         /* extract all !group */
@@ -898,7 +927,7 @@ class Notice extends Memcached_DataObject
                                 strtolower($this->content),
                                 $match);
         if (!$count) {
-            return true;
+            return $groups;
         }
 
         $profile = $this->getProfile();
@@ -930,11 +959,11 @@ class Notice extends Memcached_DataObject
                     common_log_db_error($gi, 'INSERT', __FILE__);
                 }
 
-                // FIXME: do this in an offline daemon
-
-                $this->addToGroupMemberInboxes($group);
+                $groups[] = clone($group);
             }
         }
+
+        return $groups;
     }
 
     function addToGroupInbox($group)
@@ -956,15 +985,6 @@ class Notice extends Memcached_DataObject
         return true;
     }
 
-    function addToGroupMemberInboxes($group)
-    {
-        $users = $group->getUserMembers();
-
-        foreach ($users as $id) {
-            $this->addToUserInbox($id, NOTICE_INBOX_SOURCE_GROUP);
-        }
-    }
-
     function saveReplies()
     {
         // Alternative reply format
diff --git a/classes/Session.php b/classes/Session.php
new file mode 100644 (file)
index 0000000..93fd99b
--- /dev/null
@@ -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;
+    }
+}
index f8d6756b69090c4c51e7127ba2497e4b0e1a6444..dbd722e88e9ba8e99602aeca1211e028f9623a5b 100644 (file)
@@ -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)) {
index 9b4b01ead7424f60ba7bae7db2df4152ee2ab335..27b444705d93823a67b8b519226f099e931fd939 100644 (file)
@@ -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 =
old mode 100755 (executable)
new mode 100644 (file)
index 7e9b2b7..766bed7
@@ -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
index d42bac9a6920be6fd97332b5553f364f8b96fd76..a23b41b3192cec813849f0608828ad94fd28b7af 100644 (file)
@@ -86,6 +86,9 @@ $config['sphinx']['port'] = 3312;
 // $config['xmpp']['public'][] = 'someindexer@example.net';
 // $config['xmpp']['debug'] = false;
 
+// Turn off invites
+// $config['invite']['enabled'] = false;
+
 // Default locale info
 // $config['site']['timezone'] = 'Pacific/Auckland';
 // $config['site']['language'] = 'en_NZ';
index 3f8918de62d3b8bb9d5ebbadb79834162f8f6638..2c04f680a85d587a032cd06fada5c63c8488eaa5 100644 (file)
@@ -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/Mail/mimeDecode.php b/extlib/Mail/mimeDecode.php
new file mode 100644 (file)
index 0000000..aaa870c
--- /dev/null
@@ -0,0 +1,849 @@
+<?php
+/**
+ * The Mail_mimeDecode class is used to decode mail/mime messages
+ *
+ * This class will parse a raw mime email and return
+ * the structure. Returned structure is similar to
+ * that returned by imap_fetchstructure().
+ *
+ *  +----------------------------- IMPORTANT ------------------------------+
+ *  | Usage of this class compared to native php extensions such as        |
+ *  | mailparse or imap, is slow and may be feature deficient. If available|
+ *  | you are STRONGLY recommended to use the php extensions.              |
+ *  +----------------------------------------------------------------------+
+ *
+ * Compatible with PHP versions 4 and 5
+ *
+ * LICENSE: This LICENSE is in the BSD license style.
+ * Copyright (c) 2002-2003, Richard Heyes <richard@phpguru.org>
+ * Copyright (c) 2003-2006, PEAR <pear-group@php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - Neither the name of the authors, nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this 
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category   Mail
+ * @package    Mail_Mime
+ * @author     Richard Heyes  <richard@phpguru.org>
+ * @author     George Schlossnagle <george@omniti.com>
+ * @author     Cipriano Groenendal <cipri@php.net>
+ * @author     Sean Coates <sean@php.net>
+ * @copyright  2003-2006 PEAR <pear-group@php.net>
+ * @license    http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @version    CVS: $Id: mimeDecode.php,v 1.48 2006/12/03 13:43:33 cipri Exp $
+ * @link       http://pear.php.net/package/Mail_mime
+ */
+
+
+/**
+ * require PEAR
+ *
+ * This package depends on PEAR to raise errors.
+ */
+require_once 'PEAR.php';
+
+
+/**
+ * The Mail_mimeDecode class is used to decode mail/mime messages
+ *
+ * This class will parse a raw mime email and return the structure.
+ * Returned structure is similar to that returned by imap_fetchstructure().
+ *
+ *  +----------------------------- IMPORTANT ------------------------------+
+ *  | Usage of this class compared to native php extensions such as        |
+ *  | mailparse or imap, is slow and may be feature deficient. If available|
+ *  | you are STRONGLY recommended to use the php extensions.              |
+ *  +----------------------------------------------------------------------+
+ *
+ * @category   Mail
+ * @package    Mail_Mime
+ * @author     Richard Heyes  <richard@phpguru.org>
+ * @author     George Schlossnagle <george@omniti.com>
+ * @author     Cipriano Groenendal <cipri@php.net>
+ * @author     Sean Coates <sean@php.net>
+ * @copyright  2003-2006 PEAR <pear-group@php.net>
+ * @license    http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Mail_mime
+ */
+class Mail_mimeDecode extends PEAR
+{
+    /**
+     * The raw email to decode
+     *
+     * @var    string
+     * @access private
+     */
+    var $_input;
+
+    /**
+     * The header part of the input
+     *
+     * @var    string
+     * @access private
+     */
+    var $_header;
+
+    /**
+     * The body part of the input
+     *
+     * @var    string
+     * @access private
+     */
+    var $_body;
+
+    /**
+     * If an error occurs, this is used to store the message
+     *
+     * @var    string
+     * @access private
+     */
+    var $_error;
+
+    /**
+     * Flag to determine whether to include bodies in the
+     * returned object.
+     *
+     * @var    boolean
+     * @access private
+     */
+    var $_include_bodies;
+
+    /**
+     * Flag to determine whether to decode bodies
+     *
+     * @var    boolean
+     * @access private
+     */
+    var $_decode_bodies;
+
+    /**
+     * Flag to determine whether to decode headers
+     *
+     * @var    boolean
+     * @access private
+     */
+    var $_decode_headers;
+
+    /**
+     * Constructor.
+     *
+     * Sets up the object, initialise the variables, and splits and
+     * stores the header and body of the input.
+     *
+     * @param string The input to decode
+     * @access public
+     */
+    function Mail_mimeDecode($input)
+    {
+        list($header, $body)   = $this->_splitBodyHeader($input);
+
+        $this->_input          = $input;
+        $this->_header         = $header;
+        $this->_body           = $body;
+        $this->_decode_bodies  = false;
+        $this->_include_bodies = true;
+    }
+
+    /**
+     * Begins the decoding process. If called statically
+     * it will create an object and call the decode() method
+     * of it.
+     *
+     * @param array An array of various parameters that determine
+     *              various things:
+     *              include_bodies - Whether to include the body in the returned
+     *                               object.
+     *              decode_bodies  - Whether to decode the bodies
+     *                               of the parts. (Transfer encoding)
+     *              decode_headers - Whether to decode headers
+     *              input          - If called statically, this will be treated
+     *                               as the input
+     * @return object Decoded results
+     * @access public
+     */
+    function decode($params = null)
+    {
+        // determine if this method has been called statically
+        $isStatic = !(isset($this) && get_class($this) == __CLASS__);
+
+        // Have we been called statically?
+       // If so, create an object and pass details to that.
+        if ($isStatic AND isset($params['input'])) {
+
+            $obj = new Mail_mimeDecode($params['input']);
+            $structure = $obj->decode($params);
+
+        // Called statically but no input
+        } elseif ($isStatic) {
+            return PEAR::raiseError('Called statically and no input given');
+
+        // Called via an object
+        } else {
+            $this->_include_bodies = isset($params['include_bodies']) ?
+                                    $params['include_bodies'] : false;
+            $this->_decode_bodies  = isset($params['decode_bodies']) ?
+                                    $params['decode_bodies']  : false;
+            $this->_decode_headers = isset($params['decode_headers']) ?
+                                    $params['decode_headers'] : false;
+
+            $structure = $this->_decode($this->_header, $this->_body);
+            if ($structure === false) {
+                $structure = $this->raiseError($this->_error);
+            }
+        }
+
+        return $structure;
+    }
+
+    /**
+     * Performs the decoding. Decodes the body string passed to it
+     * If it finds certain content-types it will call itself in a
+     * recursive fashion
+     *
+     * @param string Header section
+     * @param string Body section
+     * @return object Results of decoding process
+     * @access private
+     */
+    function _decode($headers, $body, $default_ctype = 'text/plain')
+    {
+        $return = new stdClass;
+        $return->headers = array();
+        $headers = $this->_parseHeaders($headers);
+
+        foreach ($headers as $value) {
+            if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) {
+                $return->headers[strtolower($value['name'])]   = array($return->headers[strtolower($value['name'])]);
+                $return->headers[strtolower($value['name'])][] = $value['value'];
+
+            } elseif (isset($return->headers[strtolower($value['name'])])) {
+                $return->headers[strtolower($value['name'])][] = $value['value'];
+
+            } else {
+                $return->headers[strtolower($value['name'])] = $value['value'];
+            }
+        }
+
+        reset($headers);
+        while (list($key, $value) = each($headers)) {
+            $headers[$key]['name'] = strtolower($headers[$key]['name']);
+            switch ($headers[$key]['name']) {
+
+                case 'content-type':
+                    $content_type = $this->_parseHeaderValue($headers[$key]['value']);
+
+                    if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) {
+                        $return->ctype_primary   = $regs[1];
+                        $return->ctype_secondary = $regs[2];
+                    }
+
+                    if (isset($content_type['other'])) {
+                        while (list($p_name, $p_value) = each($content_type['other'])) {
+                            $return->ctype_parameters[$p_name] = $p_value;
+                        }
+                    }
+                    break;
+
+                case 'content-disposition':
+                    $content_disposition = $this->_parseHeaderValue($headers[$key]['value']);
+                    $return->disposition   = $content_disposition['value'];
+                    if (isset($content_disposition['other'])) {
+                        while (list($p_name, $p_value) = each($content_disposition['other'])) {
+                            $return->d_parameters[$p_name] = $p_value;
+                        }
+                    }
+                    break;
+
+                case 'content-transfer-encoding':
+                    $content_transfer_encoding = $this->_parseHeaderValue($headers[$key]['value']);
+                    break;
+            }
+        }
+
+        if (isset($content_type)) {
+            switch (strtolower($content_type['value'])) {
+                case 'text/plain':
+                    $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
+                    $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null;
+                    break;
+
+                case 'text/html':
+                    $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
+                    $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null;
+                    break;
+
+                case 'multipart/parallel':
+                case 'multipart/appledouble': // Appledouble mail
+                case 'multipart/report': // RFC1892
+                case 'multipart/signed': // PGP
+                case 'multipart/digest':
+                case 'multipart/alternative':
+                case 'multipart/related':
+                case 'multipart/mixed':
+                    if(!isset($content_type['other']['boundary'])){
+                        $this->_error = 'No boundary found for ' . $content_type['value'] . ' part';
+                        return false;
+                    }
+
+                    $default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain';
+
+                    $parts = $this->_boundarySplit($body, $content_type['other']['boundary']);
+                    for ($i = 0; $i < count($parts); $i++) {
+                        list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]);
+                        $part = $this->_decode($part_header, $part_body, $default_ctype);
+                        if($part === false)
+                            $part = $this->raiseError($this->_error);
+                        $return->parts[] = $part;
+                    }
+                    break;
+
+                case 'message/rfc822':
+                    $obj = &new Mail_mimeDecode($body);
+                    $return->parts[] = $obj->decode(array('include_bodies' => $this->_include_bodies,
+                                                                             'decode_bodies'  => $this->_decode_bodies,
+                                                                                                                 'decode_headers' => $this->_decode_headers));
+                    unset($obj);
+                    break;
+
+                default:
+                    if(!isset($content_transfer_encoding['value']))
+                        $content_transfer_encoding['value'] = '7bit';
+                    $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $content_transfer_encoding['value']) : $body) : null;
+                    break;
+            }
+
+        } else {
+            $ctype = explode('/', $default_ctype);
+            $return->ctype_primary   = $ctype[0];
+            $return->ctype_secondary = $ctype[1];
+            $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body) : $body) : null;
+        }
+
+        return $return;
+    }
+
+    /**
+     * Given the output of the above function, this will return an
+     * array of references to the parts, indexed by mime number.
+     *
+     * @param  object $structure   The structure to go through
+     * @param  string $mime_number Internal use only.
+     * @return array               Mime numbers
+     */
+    function &getMimeNumbers(&$structure, $no_refs = false, $mime_number = '', $prepend = '')
+    {
+        $return = array();
+        if (!empty($structure->parts)) {
+            if ($mime_number != '') {
+                $structure->mime_id = $prepend . $mime_number;
+                $return[$prepend . $mime_number] = &$structure;
+            }
+            for ($i = 0; $i < count($structure->parts); $i++) {
+
+            
+                if (!empty($structure->headers['content-type']) AND substr(strtolower($structure->headers['content-type']), 0, 8) == 'message/') {
+                    $prepend      = $prepend . $mime_number . '.';
+                    $_mime_number = '';
+                } else {
+                    $_mime_number = ($mime_number == '' ? $i + 1 : sprintf('%s.%s', $mime_number, $i + 1));
+                }
+
+                $arr = &Mail_mimeDecode::getMimeNumbers($structure->parts[$i], $no_refs, $_mime_number, $prepend);
+                foreach ($arr as $key => $val) {
+                    $no_refs ? $return[$key] = '' : $return[$key] = &$arr[$key];
+                }
+            }
+        } else {
+            if ($mime_number == '') {
+                $mime_number = '1';
+            }
+            $structure->mime_id = $prepend . $mime_number;
+            $no_refs ? $return[$prepend . $mime_number] = '' : $return[$prepend . $mime_number] = &$structure;
+        }
+        
+        return $return;
+    }
+
+    /**
+     * Given a string containing a header and body
+     * section, this function will split them (at the first
+     * blank line) and return them.
+     *
+     * @param string Input to split apart
+     * @return array Contains header and body section
+     * @access private
+     */
+    function _splitBodyHeader($input)
+    {
+        if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) {
+            return array($match[1], $match[2]);
+        }
+        $this->_error = 'Could not split header and body';
+        return false;
+    }
+
+    /**
+     * Parse headers given in $input and return
+     * as assoc array.
+     *
+     * @param string Headers to parse
+     * @return array Contains parsed headers
+     * @access private
+     */
+    function _parseHeaders($input)
+    {
+
+        if ($input !== '') {
+            // Unfold the input
+            $input   = preg_replace("/\r?\n/", "\r\n", $input);
+            $input   = preg_replace("/\r\n(\t| )+/", ' ', $input);
+            $headers = explode("\r\n", trim($input));
+
+            foreach ($headers as $value) {
+                $hdr_name = substr($value, 0, $pos = strpos($value, ':'));
+                $hdr_value = substr($value, $pos+1);
+                if($hdr_value[0] == ' ')
+                    $hdr_value = substr($hdr_value, 1);
+
+                $return[] = array(
+                                  'name'  => $hdr_name,
+                                  'value' => $this->_decode_headers ? $this->_decodeHeader($hdr_value) : $hdr_value
+                                 );
+            }
+        } else {
+            $return = array();
+        }
+
+        return $return;
+    }
+
+    /**
+     * Function to parse a header value,
+     * extract first part, and any secondary
+     * parts (after ;) This function is not as
+     * robust as it could be. Eg. header comments
+     * in the wrong place will probably break it.
+     *
+     * @param string Header value to parse
+     * @return array Contains parsed result
+     * @access private
+     */
+    function _parseHeaderValue($input)
+    {
+
+        if (($pos = strpos($input, ';')) !== false) {
+
+            $return['value'] = trim(substr($input, 0, $pos));
+            $input = trim(substr($input, $pos+1));
+
+            if (strlen($input) > 0) {
+
+                // This splits on a semi-colon, if there's no preceeding backslash
+                // Now works with quoted values; had to glue the \; breaks in PHP
+                // the regex is already bordering on incomprehensible
+                $splitRegex = '/([^;\'"]*[\'"]([^\'"]*([^\'"]*)*)[\'"][^;\'"]*|([^;]+))(;|$)/';
+                preg_match_all($splitRegex, $input, $matches);
+                $parameters = array();
+                for ($i=0; $i<count($matches[0]); $i++) {
+                    $param = $matches[0][$i];
+                    while (substr($param, -2) == '\;') {
+                        $param .= $matches[0][++$i];
+                    }
+                    $parameters[] = $param;
+                }
+
+                for ($i = 0; $i < count($parameters); $i++) {
+                    $param_name  = trim(substr($parameters[$i], 0, $pos = strpos($parameters[$i], '=')), "'\";\t\\ ");
+                    $param_value = trim(str_replace('\;', ';', substr($parameters[$i], $pos + 1)), "'\";\t\\ ");
+                    if ($param_value[0] == '"') {
+                        $param_value = substr($param_value, 1, -1);
+                    }
+                    $return['other'][$param_name] = $param_value;
+                    $return['other'][strtolower($param_name)] = $param_value;
+                }
+            }
+        } else {
+            $return['value'] = trim($input);
+        }
+
+        return $return;
+    }
+
+    /**
+     * This function splits the input based
+     * on the given boundary
+     *
+     * @param string Input to parse
+     * @return array Contains array of resulting mime parts
+     * @access private
+     */
+    function _boundarySplit($input, $boundary)
+    {
+        $parts = array();
+
+        $bs_possible = substr($boundary, 2, -2);
+        $bs_check = '\"' . $bs_possible . '\"';
+
+        if ($boundary == $bs_check) {
+            $boundary = $bs_possible;
+        }
+
+        $tmp = explode('--' . $boundary, $input);
+
+        for ($i = 1; $i < count($tmp) - 1; $i++) {
+            $parts[] = $tmp[$i];
+        }
+
+        return $parts;
+    }
+
+    /**
+     * Given a header, this function will decode it
+     * according to RFC2047. Probably not *exactly*
+     * conformant, but it does pass all the given
+     * examples (in RFC2047).
+     *
+     * @param string Input header value to decode
+     * @return string Decoded header value
+     * @access private
+     */
+    function _decodeHeader($input)
+    {
+        // Remove white space between encoded-words
+        $input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input);
+
+        // For each encoded-word...
+        while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) {
+
+            $encoded  = $matches[1];
+            $charset  = $matches[2];
+            $encoding = $matches[3];
+            $text     = $matches[4];
+
+            switch (strtolower($encoding)) {
+                case 'b':
+                    $text = base64_decode($text);
+                    break;
+
+                case 'q':
+                    $text = str_replace('_', ' ', $text);
+                    preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
+                    foreach($matches[1] as $value)
+                        $text = str_replace('='.$value, chr(hexdec($value)), $text);
+                    break;
+            }
+
+            $input = str_replace($encoded, $text, $input);
+        }
+
+        return $input;
+    }
+
+    /**
+     * Given a body string and an encoding type,
+     * this function will decode and return it.
+     *
+     * @param  string Input body to decode
+     * @param  string Encoding type to use.
+     * @return string Decoded body
+     * @access private
+     */
+    function _decodeBody($input, $encoding = '7bit')
+    {
+        switch (strtolower($encoding)) {
+            case '7bit':
+                return $input;
+                break;
+
+            case 'quoted-printable':
+                return $this->_quotedPrintableDecode($input);
+                break;
+
+            case 'base64':
+                return base64_decode($input);
+                break;
+
+            default:
+                return $input;
+        }
+    }
+
+    /**
+     * Given a quoted-printable string, this
+     * function will decode and return it.
+     *
+     * @param  string Input body to decode
+     * @return string Decoded body
+     * @access private
+     */
+    function _quotedPrintableDecode($input)
+    {
+        // Remove soft line breaks
+        $input = preg_replace("/=\r?\n/", '', $input);
+
+        // Replace encoded characters
+               $input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input);
+
+        return $input;
+    }
+
+    /**
+     * Checks the input for uuencoded files and returns
+     * an array of them. Can be called statically, eg:
+     *
+     * $files =& Mail_mimeDecode::uudecode($some_text);
+     *
+     * It will check for the begin 666 ... end syntax
+     * however and won't just blindly decode whatever you
+     * pass it.
+     *
+     * @param  string Input body to look for attahcments in
+     * @return array  Decoded bodies, filenames and permissions
+     * @access public
+     * @author Unknown
+     */
+    function &uudecode($input)
+    {
+        // Find all uuencoded sections
+        preg_match_all("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", $input, $matches);
+
+        for ($j = 0; $j < count($matches[3]); $j++) {
+
+            $str      = $matches[3][$j];
+            $filename = $matches[2][$j];
+            $fileperm = $matches[1][$j];
+
+            $file = '';
+            $str = preg_split("/\r?\n/", trim($str));
+            $strlen = count($str);
+
+            for ($i = 0; $i < $strlen; $i++) {
+                $pos = 1;
+                $d = 0;
+                $len=(int)(((ord(substr($str[$i],0,1)) -32) - ' ') & 077);
+
+                while (($d + 3 <= $len) AND ($pos + 4 <= strlen($str[$i]))) {
+                    $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
+                    $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
+                    $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
+                    $c3 = (ord(substr($str[$i],$pos+3,1)) ^ 0x20);
+                    $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
+
+                    $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));
+
+                    $file .= chr(((($c2 - ' ') & 077) << 6) |  (($c3 - ' ') & 077));
+
+                    $pos += 4;
+                    $d += 3;
+                }
+
+                if (($d + 2 <= $len) && ($pos + 3 <= strlen($str[$i]))) {
+                    $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
+                    $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
+                    $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
+                    $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
+
+                    $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));
+
+                    $pos += 3;
+                    $d += 2;
+                }
+
+                if (($d + 1 <= $len) && ($pos + 2 <= strlen($str[$i]))) {
+                    $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
+                    $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
+                    $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
+
+                }
+            }
+            $files[] = array('filename' => $filename, 'fileperm' => $fileperm, 'filedata' => $file);
+        }
+
+        return $files;
+    }
+
+    /**
+     * getSendArray() returns the arguments required for Mail::send()
+     * used to build the arguments for a mail::send() call 
+     *
+     * Usage:
+     * $mailtext = Full email (for example generated by a template)
+     * $decoder = new Mail_mimeDecode($mailtext);
+     * $parts =  $decoder->getSendArray();
+     * if (!PEAR::isError($parts) {
+     *     list($recipents,$headers,$body) = $parts;
+     *     $mail = Mail::factory('smtp');
+     *     $mail->send($recipents,$headers,$body);
+     * } else {
+     *     echo $parts->message;
+     * }
+     * @return mixed   array of recipeint, headers,body or Pear_Error
+     * @access public
+     * @author Alan Knowles <alan@akbkhome.com>
+     */
+    function getSendArray()
+    {
+        // prevent warning if this is not set
+        $this->_decode_headers = FALSE;
+        $headerlist =$this->_parseHeaders($this->_header);
+        $to = "";
+        if (!$headerlist) {
+            return $this->raiseError("Message did not contain headers");
+        }
+        foreach($headerlist as $item) {
+            $header[$item['name']] = $item['value'];
+            switch (strtolower($item['name'])) {
+                case "to":
+                case "cc":
+                case "bcc":
+                    $to = ",".$item['value'];
+                default:
+                   break;
+            }
+        }
+        if ($to == "") {
+            return $this->raiseError("Message did not contain any recipents");
+        }
+        $to = substr($to,1);
+        return array($to,$header,$this->_body);
+    } 
+
+    /**
+     * Returns a xml copy of the output of
+     * Mail_mimeDecode::decode. Pass the output in as the
+     * argument. This function can be called statically. Eg:
+     *
+     * $output = $obj->decode();
+     * $xml    = Mail_mimeDecode::getXML($output);
+     *
+     * The DTD used for this should have been in the package. Or
+     * alternatively you can get it from cvs, or here:
+     * http://www.phpguru.org/xmail/xmail.dtd.
+     *
+     * @param  object Input to convert to xml. This should be the
+     *                output of the Mail_mimeDecode::decode function
+     * @return string XML version of input
+     * @access public
+     */
+    function getXML($input)
+    {
+        $crlf    =  "\r\n";
+        $output  = '<?xml version=\'1.0\'?>' . $crlf .
+                   '<!DOCTYPE email SYSTEM "http://www.phpguru.org/xmail/xmail.dtd">' . $crlf .
+                   '<email>' . $crlf .
+                   Mail_mimeDecode::_getXML($input) .
+                   '</email>';
+
+        return $output;
+    }
+
+    /**
+     * Function that does the actual conversion to xml. Does a single
+     * mimepart at a time.
+     *
+     * @param  object  Input to convert to xml. This is a mimepart object.
+     *                 It may or may not contain subparts.
+     * @param  integer Number of tabs to indent
+     * @return string  XML version of input
+     * @access private
+     */
+    function _getXML($input, $indent = 1)
+    {
+        $htab    =  "\t";
+        $crlf    =  "\r\n";
+        $output  =  '';
+        $headers = @(array)$input->headers;
+
+        foreach ($headers as $hdr_name => $hdr_value) {
+
+            // Multiple headers with this name
+            if (is_array($headers[$hdr_name])) {
+                for ($i = 0; $i < count($hdr_value); $i++) {
+                    $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value[$i], $indent);
+                }
+
+            // Only one header of this sort
+            } else {
+                $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value, $indent);
+            }
+        }
+
+        if (!empty($input->parts)) {
+            for ($i = 0; $i < count($input->parts); $i++) {
+                $output .= $crlf . str_repeat($htab, $indent) . '<mimepart>' . $crlf .
+                           Mail_mimeDecode::_getXML($input->parts[$i], $indent+1) .
+                           str_repeat($htab, $indent) . '</mimepart>' . $crlf;
+            }
+        } elseif (isset($input->body)) {
+            $output .= $crlf . str_repeat($htab, $indent) . '<body><![CDATA[' .
+                       $input->body . ']]></body>' . $crlf;
+        }
+
+        return $output;
+    }
+
+    /**
+     * Helper function to _getXML(). Returns xml of a header.
+     *
+     * @param  string  Name of header
+     * @param  string  Value of header
+     * @param  integer Number of tabs to indent
+     * @return string  XML version of input
+     * @access private
+     */
+    function _getXML_helper($hdr_name, $hdr_value, $indent)
+    {
+        $htab   = "\t";
+        $crlf   = "\r\n";
+        $return = '';
+
+        $new_hdr_value = ($hdr_name != 'received') ? Mail_mimeDecode::_parseHeaderValue($hdr_value) : array('value' => $hdr_value);
+        $new_hdr_name  = str_replace(' ', '-', ucwords(str_replace('-', ' ', $hdr_name)));
+
+        // Sort out any parameters
+        if (!empty($new_hdr_value['other'])) {
+            foreach ($new_hdr_value['other'] as $paramname => $paramvalue) {
+                $params[] = str_repeat($htab, $indent) . $htab . '<parameter>' . $crlf .
+                            str_repeat($htab, $indent) . $htab . $htab . '<paramname>' . htmlspecialchars($paramname) . '</paramname>' . $crlf .
+                            str_repeat($htab, $indent) . $htab . $htab . '<paramvalue>' . htmlspecialchars($paramvalue) . '</paramvalue>' . $crlf .
+                            str_repeat($htab, $indent) . $htab . '</parameter>' . $crlf;
+            }
+
+            $params = implode('', $params);
+        } else {
+            $params = '';
+        }
+
+        $return = str_repeat($htab, $indent) . '<header>' . $crlf .
+                  str_repeat($htab, $indent) . $htab . '<headername>' . htmlspecialchars($new_hdr_name) . '</headername>' . $crlf .
+                  str_repeat($htab, $indent) . $htab . '<headervalue>' . htmlspecialchars($new_hdr_value['value']) . '</headervalue>' . $crlf .
+                  $params .
+                  str_repeat($htab, $indent) . '</header>' . $crlf;
+
+        return $return;
+    }
+
+} // End of class
index b147443d79bcb28ac88e67bef52dbe0d64c71c36..befaf60a77151cc533743ab5adb4211a05971d94 100644 (file)
@@ -27,7 +27,7 @@
  */
 
 /** XMPPHP_XMLStream */
-require_once "XMPP.php";
+require_once dirname(__FILE__) . "/XMPP.php";
 
 /**
  * XMPPHP Main Class
index 0fcfea375e1d4110925dbe63a34310985e232dbb..d33411ec54140dafc1c527c946d05cbc931807c9 100644 (file)
  */
 
 /** 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;
                
index 73fbd265840b878e176aba334a7cf984bca72689..429f45e565eb57648930988c8133b73bd6d26c5d 100644 (file)
@@ -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
index cb6a0fe6032677522b9cb42f1d360932f17f1fd5..5f9a048f2c7225917dcc56bfbb1b7326067ef4f9 100644 (file)
--- 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)) {
index b94a9293607e7928659c4da53e09323283d61f5b..570b08edf473b13e709ece605656a279d89016de 100644 (file)
@@ -72,6 +72,12 @@ function checkPrereqs()
          <?
             $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;
+       }
 
        return $pass;
 }
index c9168506a5ae2410277802e6cb2fa9e6370a4d6e..ffbd5daac6b16384d7311e3e62f92cd438ebbae1 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (c) 2009 Alvaro A. Lima Jr http://alvarojunior.com/jquery/joverlay.html
  * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
- * Version: 0.6 (Abr 23, 2009)
+ * Version: 0.7.1 (JUN 15, 2009
  * Requires: jQuery 1.3+
+ * Packer from http://dean.edwards.name/packer/
  */
-(function($){var f=$.browser.msie&&$.browser.version==6.0;var g=null;$.fn.jOverlay=function(b){var b=$.extend({},$.fn.jOverlay.options,b);if(g!=null){clearTimeout(g)}var c=this.is('*')?this:'#jOverlayContent';var d=f?'absolute':'fixed';var e=b.imgLoading?"<img id='jOverlayLoading' src='"+b.imgLoading+"' style='position:"+d+"; z-index:"+(b.zIndex+9)+";'/>":'';$('body').prepend(e+"<div id='jOverlay' />"+"<div id='jOverlayContent' style='position:"+d+"; z-index:"+(b.zIndex+5)+"; display:none;'/>");$('#jOverlayLoading').load(function(){if(b.center){$.center(this)}});if(f){$("select").hide();$("#jOverlayContent select").show()}$('#jOverlay').css({backgroundColor:b.color,position:d,top:'0px',left:'0px',filter:'alpha(opacity='+(b.opacity*100)+')',opacity:b.opacity,zIndex:b.zIndex,width:!f?'100%':$(window).width()+'px',height:!f?'100%':$(document).height()+'px'}).show();if(this.is('*')){$('#jOverlayContent').html(this.addClass('jOverlayChildren').show()).show();if(b.center){$.center('#jOverlayContent')}if(!b.url&&$.isFunction(b.success)){b.success(this.html())}}if(b.url){$.ajax({type:b.method,data:b.data,url:b.url,success:function(a){$('#jOverlayLoading').fadeOut(600);$(c).html(a).show();if(b.center){$.center('#jOverlayContent')}if($.isFunction(b.success)){b.success(a)}}})}if(f){$(window).scroll(function(){if(b.center){$.center('#jOverlayContent')}});$(window).resize(function(){$('#jOverlay').css({width:$(window).width()+'px',height:$(document).height()+'px'});if(b.center){$.center('#jOverlayContent')}})}$(document).keydown(function(a){if(a.keyCode==27){$.closeOverlay()}});if(b.bgClickToClose){$('#jOverlay').click($.closeOverlay)}if(Number(b.timeout)>0){g=setTimeout($.closeOverlay,Number(b.timeout))}};$.center=function(a){var a=$(a);var b=a.height();var c=a.width();a.css({width:c+'px',marginLeft:'-'+(c/2)+'px',marginTop:'-'+b/2+'px',height:'auto',top:!f?'50%':$(window).scrollTop()+($(window).height()/2)+"px",left:'50%'})};$.fn.jOverlay.options={method:'GET',data:'',url:'',color:'#000',opacity:'0.6',zIndex:9999,center:true,imgLoading:'',bgClickToClose:true,success:null,timeout:0};$.closeOverlay=function(){if(f){$("select").show()}$('#jOverlayContent .jOverlayChildren').hide().prependTo($('body'));$('#jOverlayLoading, #jOverlayContent, #jOverlay').remove()}})(jQuery);
\ No newline at end of file
+(function($){var g=$.browser.msie&&$.browser.version==6.0;var h=null;var i=null;$.fn.jOverlay=function(b){if($('#jOverlay').length){$.closeOverlay()}i=null;if(h!==null){clearTimeout(h)}var b=$.extend({},$.fn.jOverlay.options,b);function center(a){if(b.center){$.center(a)}}var c=this.is('*')?this:'#jOverlayContent';var d=g?'absolute':'fixed';var e=/([^\/\\]+)\.(png|gif|jpeg|jpg|bmp)$/i.test(b.url);var f=b.imgLoading?"<img id='jOverlayLoading' src='"+b.imgLoading+"' style='position:"+d+"; z-index:"+(b.zIndex+9)+";'/>":'';$('body').prepend(f+"<div id='jOverlay' />"+"<div id='jOverlayContent' style='position:"+d+"; z-index:"+(b.zIndex+5)+"; display:none;'/>");$('#jOverlayLoading').load(function(){center(this)});if(g){$('select').hide();$('#jOverlayContent select').show()}$('#jOverlay').css({backgroundColor:b.color,position:d,top:'0px',left:'0px',filter:'alpha(opacity='+(b.opacity*100)+')',opacity:b.opacity,zIndex:b.zIndex,width:!g?'100%':$(window).width()+'px',height:!g?'100%':$(document).height()+'px'}).show();if(this.is('*')){i=this.prev();$('#jOverlayContent').html(this.show().attr('display',b.autoHide?'none':this.css('display')));if(!e){center('#jOverlayContent');$('#jOverlayContent').show();if(!b.url&&$.isFunction(b.success)){b.success(this)}}}if(e){$('<img/>').load(function(){var a=$.resize(this.width,this.height);$(this).css({width:a.width,height:a.height});$(c).html(this);center('#jOverlayContent');$('#jOverlayLoading').fadeOut(500);$('#jOverlayContent').show();if($.isFunction(b.success)){b.success(this)}}).error(function(){alert('Image ('+b.url+') not found.');$.closeOverlay()}).attr({'src':b.url,'alt':b.url})}if(b.url&&!e){$.ajax({type:b.method,data:b.data,url:b.url,success:function(a){$('#jOverlayLoading').fadeOut(500);$(c).html(a).show();center('#jOverlayContent');if($.isFunction(b.success)){b.success(a)}},error:function(){alert('URL ('+b.url+') not found.');$.closeOverlay()}})}if(g){$(window).scroll(function(){center('#jOverlayContent')});$(window).resize(function(){$('#jOverlay').css({width:$(window).width()+'px',height:$(document).height()+'px'});center('#jOverlayContent')})}$(document).keydown(function(a){if(a.keyCode==27){$.closeOverlay()}});if(b.bgClickToClose){$('#jOverlay').click($.closeOverlay)}if(Number(b.timeout)>0){jOverlayTimer=setTimeout($.closeOverlay,Number(b.timeout))}$('#jOverlayContent').css(b.css||{})};$.resize=function(a,b){var x=$(window).width()-150;var y=$(window).height()-150;if(a>x){b=b*(x/a);a=x;if(b>y){a=a*(y/b);b=y}}else if(b>y){a=a*(y/b);b=y;if(a>x){b=b*(x/a);a=x}}return{width:a,height:b}};$.center=function(a){var a=$(a);var b=a.width();a.css({width:b+'px',marginLeft:'-'+(b/2)+'px',marginTop:'-'+a.height()/2+'px',height:'auto',top:!g?'35%':$(window).scrollTop()+($(window).height()/2)+'px',left:'50%'})};$.fn.jOverlay.options={method:'GET',data:'',url:'',color:'#000',opacity:'0.6',zIndex:9999,center:true,imgLoading:'',bgClickToClose:true,success:null,timeout:0,autoHide:true,css:{}};$.closeOverlay=function(){if(g){$("select").show()}if(i!==null){if(i!==null){var a=$('#jOverlayContent').children();i.after(a.css('display',a.attr('display')));a.removeAttr('display')}}$('#jOverlayLoading, #jOverlayContent, #jOverlay').remove()}})(jQuery);
index 833b19adcb50ebd3c4715f0a69f5bb584124afed..dda86294ed99abda715578176d12adf860c3a397 100644 (file)
@@ -11,7 +11,7 @@ $(document).ready(function() {
         C = $(S).val();
         switch (parseInt(S.id.slice(-1))) {
             case 1: default:
-                $('html, body').css({'background-color':C});
+                $('body').css({'background-color':C});
                 break;
             case 2:
                 $('#content, #site_nav_local_views .current a').css({'background-color':C});
@@ -90,6 +90,7 @@ $(document).ready(function() {
     });
     $('#design_background-image_on').focus(function() {
         $('body').css({'background-image':'url('+$('#design_background-image_onoff img')[0].src+')'});
+        $('body').css({'background-attachment': 'fixed'});
     });
 
     $('#design_background-image_repeat').click(function() {
index e7c54b74accb245d8397105efe30cd3af19ecb67..1e6dc725117cf5c3e3247a1bcc5ec31acaaf67d4 100644 (file)
@@ -279,7 +279,9 @@ function NoticeAttachments() {
             $('#jOverlayContent').append('<button>&#215;</button>');
             $('#jOverlayContent button').click($.closeOverlay);
         },
-        timeout : 0
+        timeout : 0,
+        autoHide : true,
+        css : {'max-width':'502px'}
     };
 
     $('#content .notice a.attachment').click(function() {
index 89a8c8f4d3aa1c5af24440a528f865db5287c6f9..12d122f120279d9ba5b1ecfc755395505a1b8c04 100644 (file)
@@ -422,11 +422,13 @@ class Action extends HTMLOutputter // lawsuit
                     $this->menuItem(common_local_url('smssettings'),
                                     _('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
                 }
-                $this->menuItem(common_local_url('invite'),
-                                _('Invite'),
-                                sprintf(_('Invite friends and colleagues to join you on %s'),
-                                        common_config('site', 'name')),
-                                false, 'nav_invitecontact');
+                if (common_config('invite', 'enabled')) {
+                    $this->menuItem(common_local_url('invite'),
+                                    _('Invite'),
+                                    sprintf(_('Invite friends and colleagues to join you on %s'),
+                                            common_config('site', 'name')),
+                                    false, 'nav_invitecontact');
+                }
                 $this->menuItem(common_local_url('logout'),
                                 _('Logout'), _('Logout from the site'), false, 'nav_logout');
             }
index bb1a4255da7fa9a5d7869f93eb7ee8e97d502812..e10f24b3b8c4f47cffae7b4e13df5c3d2b7025d4 100644 (file)
@@ -175,6 +175,8 @@ $config =
               'host' => null, # only set if != server
               'debug' => false, # print extra debug info
               'public' => array()), # JIDs of users who want to receive the public stream
+        'invite' =>
+        array('enabled' => true),
         'sphinx' =>
         array('enabled' => false,
               'server' => 'localhost',
@@ -254,6 +256,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');
index a0df00bdcc852cc434f025ed6f062aa4496a653d..9d89c63e781eb2e25353c5501850510cb87cc612 100644 (file)
@@ -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()
index 9650679ac5b620c51f356c1d57d07e3235abfbac..fbffdb208f1e73a35e03497768f61e8f304beadc 100644 (file)
@@ -35,6 +35,20 @@ if (!defined('LACONICA')) {
 require_once INSTALLDIR . '/lib/accountsettingsaction.php';
 require_once INSTALLDIR . '/lib/webcolor.php';
 
+/**
+ * Base class for setting a user or group design
+ *
+ * Shows the design setting form and also handles some things like saving
+ * background images, and fetching a default design
+ *
+ * @category Settings
+ * @package  Laconica
+ * @author   Zach Copley <zach@controlyourself.ca>
+ * @author   Sarven Capadisli <csarven@controlyourself.ca>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://laconi.ca/
+ */
+
 class DesignSettingsAction extends AccountSettingsAction
 {
 
@@ -63,6 +77,14 @@ class DesignSettingsAction extends AccountSettingsAction
         'with a background image and a colour palette of your choice.');
     }
 
+    /**
+     * Shows the design settings form
+     *
+     * @param Design $design a working design to show
+     *
+     * @return nothing
+     */
+
     function showDesignForm($design)
     {
 
@@ -94,7 +116,8 @@ class DesignSettingsAction extends AccountSettingsAction
 
         if (!empty($design->backgroundimage)) {
 
-            $this->elementStart('li', array('id' => 'design_background-image_onoff'));
+            $this->elementStart('li', array('id' =>
+                'design_background-image_onoff'));
 
             $this->element('img', array('src' =>
                 Design::url($design->backgroundimage)));
@@ -136,7 +159,7 @@ class DesignSettingsAction extends AccountSettingsAction
             $this->elementStart('li');
             $this->checkbox('design_background-image_repeat',
                             _('Tile background image'),
-                            ($design->disposition & BACKGROUND_TILE) ? true : false );
+                            ($design->disposition & BACKGROUND_TILE) ? true : false);
             $this->elementEnd('li');
         }
 
@@ -212,18 +235,19 @@ class DesignSettingsAction extends AccountSettingsAction
                                          'maxlength' => '7',
                                          'size' => '7',
                                          'value' => '#' . $lcolor->hexValue()));
+            $this->elementEnd('li');
 
-           $this->elementEnd('li');
+        } catch (WebColorException $e) {
+            common_log(LOG_ERR, 'Bad color values in design ID: ' .$design->id);
+        }
 
-       } catch (WebColorException $e) {
-           common_log(LOG_ERR, 'Bad color values in design ID: ' .
-               $design->id);
-       }
+        $this->elementEnd('ul');
+        $this->elementEnd('fieldset');
 
-       $this->elementEnd('ul');
-       $this->elementEnd('fieldset');
+        $this->submit('defaults', _('Use defaults'), 'submit form_action-default',
+            'defaults', _('Restore default designs'));
 
-       $this->element('input', array('id' => 'settings_design_reset',
+        $this->element('input', array('id' => 'settings_design_reset',
                                      'type' => 'reset',
                                      'value' => 'Reset',
                                      'class' => 'submit form_action-primary',
@@ -271,8 +295,8 @@ class DesignSettingsAction extends AccountSettingsAction
 
         if ($this->arg('save')) {
             $this->saveDesign();
-        } else if ($this->arg('reset')) {
-            $this->resetDesign();
+        } else if ($this->arg('defaults')) {
+            $this->restoreDefaults();
         } else {
             $this->showForm(_('Unexpected form submission.'));
         }
@@ -316,7 +340,7 @@ class DesignSettingsAction extends AccountSettingsAction
     }
 
     /**
-     * Get a default user design
+     * Get a default design
      *
      * @return Design design
      */
@@ -358,7 +382,16 @@ class DesignSettingsAction extends AccountSettingsAction
         return $design;
     }
 
-    function saveBackgroundImage($design) {
+    /**
+     * Save the background image, if any, and set its disposition
+     *
+     * @param Design $design a working design to attach the img to
+     *
+     * @return nothing
+     */
+
+    function saveBackgroundImage($design)
+    {
 
         // Now that we have a Design ID we can add a file to the design.
         // XXX: This is an additional DB hit, but figured having the image
@@ -371,12 +404,12 @@ class DesignSettingsAction extends AccountSettingsAction
             $filepath = null;
 
             try {
-                    $imagefile =
-                        ImageFile::fromUpload('design_background-image_file');
-                } catch (Exception $e) {
-                    $this->showForm($e->getMessage());
-                    return;
-                }
+                $imagefile =
+                    ImageFile::fromUpload('design_background-image_file');
+            } catch (Exception $e) {
+                $this->showForm($e->getMessage());
+                return;
+            }
 
             $filename = Design::filename($design->id,
                 image_type_to_extension($imagefile->type),
@@ -386,7 +419,14 @@ class DesignSettingsAction extends AccountSettingsAction
 
             move_uploaded_file($imagefile->filepath, $filepath);
 
+            // delete any old backround img laying around
+
+            if (isset($design->backgroundimage)) {
+                @unlink(Design::path($design->backgroundimage));
+            }
+
             $original = clone($design);
+
             $design->backgroundimage = $filename;
 
             // default to on, no tile
@@ -403,4 +443,35 @@ class DesignSettingsAction extends AccountSettingsAction
         }
     }
 
+    /**
+     * Restore the user or group design to system defaults
+     *
+     * @return nothing
+     */
+
+    function restoreDefaults()
+    {
+        $design   = $this->getWorkingDesign();
+        $default  = $this->defaultDesign();
+        $original = clone($design);
+
+        $design->backgroundcolor = $default->backgroundcolor;
+        $design->contentcolor    = $default->contentcolor;
+        $design->sidebarcolor    = $default->sidebarcolor;
+        $design->textcolor       = $default->textcolor;
+        $design->linkcolor       = $default->linkcolor;
+
+        $design->setDisposition(false, true, false);
+
+        $result = $design->update($original);
+
+        if ($result === false) {
+            common_log_db_error($design, 'UPDATE', __FILE__);
+            $this->showForm(_('Couldn\'t update your design.'));
+            return;
+        }
+
+        $this->showForm(_('Design defaults restored.'), true);
+    }
+
 }
index a445750f7e00eee711f054a200c7ebc0dbd0f75e..1ae90d53bdeb534afd8a65a1f5f51c5b90a2b480 100644 (file)
@@ -213,12 +213,14 @@ class FacebookAction extends Action
             array('href' => 'index.php', 'title' => _('Home')), _('Home'));
         $this->elementEnd('li');
 
-        $this->elementStart('li',
-            array('class' =>
-                ($this->action == 'facebookinvite') ? 'current' : 'facebook_invite'));
-        $this->element('a',
-            array('href' => 'invite.php', 'title' => _('Invite')), _('Invite'));
-        $this->elementEnd('li');
+        if (common_config('invite', 'enabled')) {
+            $this->elementStart('li',
+                array('class' =>
+                    ($this->action == 'facebookinvite') ? 'current' : 'facebook_invite'));
+            $this->element('a',
+                array('href' => 'invite.php', 'title' => _('Invite')), _('Invite'));
+            $this->elementEnd('li');
+        }
 
         $this->elementStart('li',
             array('class' =>
index cd6498d30b5d108677080a4b1494efa7e54d9a90..3ea3dd2aa0a5237412a980fb1266fce75d10e9e9 100644 (file)
@@ -108,7 +108,7 @@ function get_all_languages() {
                'el'      => array('q' => 0.1, 'lang' => 'el',    'name' => 'Greek', 'direction' => 'ltr'),
                'en-us'   => array('q' => 1, 'lang' => 'en_US', 'name' => 'English (US)', 'direction' => 'ltr'),
                'en-gb'   => array('q' => 1, 'lang' => 'en_GB', 'name' => 'English (British)', 'direction' => 'ltr'),
-               'en'      => array('q' => 1, 'lang' => 'en',    'name' => 'English', 'direction' => 'ltr'),
+               'en'      => array('q' => 1, 'lang' => 'en_US',    'name' => 'English (US)', 'direction' => 'ltr'),
                'es'      => array('q' => 1, 'lang' => 'es',    'name' => 'Spanish', 'direction' => 'ltr'),
                'fi'      => array('q' => 1, 'lang' => 'fi', 'name' => 'Finnish', 'direction' => 'ltr'),
                'fr-fr'   => array('q' => 1, 'lang' => 'fr_FR', 'name' => 'French', 'direction' => 'ltr'),
index ae403c65e24f815f4f38b56b9ec081e760092074..c1c4f3309a24011b60e72de070a5fcef0267ad56 100644 (file)
@@ -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);
         }
index 1f39c60dc50207449c6ddba1a196560d0a1a390c..784ea988237dec40aacf38193335bafc100c1051 100644 (file)
@@ -152,6 +152,10 @@ class Router
         $m->connect('search/notice/rss?q=:q', array('action' => 'noticesearchrss'),
                     array('q' => '.+'));
 
+        $m->connect('attachment/:attachment',
+                    array('action' => 'attachment'),
+                    array('attachment' => '[0-9]+'));
+
         $m->connect('attachment/:attachment/ajax',
                     array('action' => 'attachment_ajax'),
                     array('attachment' => '[0-9]+'));
index 4a9b36ae8fa1a198c7d2cb7d2be8f8732c4b62cb..52099192324ada24ea0f5c0c10f7ba199612dd37 100644 (file)
@@ -100,7 +100,7 @@ class SubGroupNav extends Widget
                                          $this->user->nickname),
                                  $action == 'usergroups',
                                  'nav_usergroups');
-            if (!is_null($cur) && $this->user->id === $cur->id) {
+            if (common_config('invite', 'enabled') && !is_null($cur) && $this->user->id === $cur->id) {
                 $this->out->menuItem(common_local_url('invite'),
                                      _('Invite'),
                                      sprintf(_('Invite friends and colleagues to join you on %s'),
index 9a51477f40d627025f9bed9ef3a73909c6b54cd7..27210458192dcdec6ed8875803858fc074ebc4f9 100644 (file)
@@ -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);
+}
index a366985be424432c076dadadd8fe54cc922a9088..d45d2718c360106d5f96d6cbafa31ea954bbd761 100644 (file)
@@ -69,95 +69,153 @@ class FBConnectPlugin extends Plugin
     // Add in xmlns:fb
     function onStartShowHTML($action)
     {
-        // XXX: Horrible hack to make Safari, FF2, and Chrome work with
-        // Facebook Connect. These browser cannot use Facebook's
-        // DOM parsing routines unless the mime type of the page is
-        // text/html even though Facebook Connect uses XHTML.  This is
-        // A bug in Facebook Connect, and this is a temporary solution
-        // until they fix their JavaScript libs.
-        header('Content-Type: text/html');
 
-        $action->extraHeaders();
+        if ($this->requiresFB($action)) {
 
-        $action->startXML('html',
-            '-//W3C//DTD XHTML 1.0 Strict//EN',
-            'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
+            // XXX: Horrible hack to make Safari, FF2, and Chrome work with
+            // Facebook Connect. These browser cannot use Facebook's
+            // DOM parsing routines unless the mime type of the page is
+            // text/html even though Facebook Connect uses XHTML.  This is
+            // A bug in Facebook Connect, and this is a temporary solution
+            // until they fix their JavaScript libs.
+            header('Content-Type: text/html');
 
-        $language = $action->getLanguage();
+            $action->extraHeaders();
 
-        $action->elementStart('html',
-            array('xmlns'  => 'http://www.w3.org/1999/xhtml',
-                  'xmlns:fb' => 'http://www.facebook.com/2008/fbml',
-                  'xml:lang' => $language,
-                  'lang'     => $language));
+            $action->startXML('html',
+                '-//W3C//DTD XHTML 1.0 Strict//EN',
+                'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
 
-        return false;
+            $language = $action->getLanguage();
+
+            $action->elementStart('html',
+                array('xmlns'  => 'http://www.w3.org/1999/xhtml',
+                      'xmlns:fb' => 'http://www.facebook.com/2008/fbml',
+                      'xml:lang' => $language,
+                      'lang'     => $language));
+
+            return false;
+
+        } else {
+
+            return true;
+        }
     }
 
     // Note: this script needs to appear in the <body>
 
     function onStartShowHeader($action)
     {
-        $apikey = common_config('facebook', 'apikey');
-        $plugin_path = common_path('plugins/FBConnect');
-
-        $login_url = common_local_url('FBConnectAuth');
-        $logout_url = common_local_url('logout');
-
-        // XXX: Facebook says we don't need this FB_RequireFeatures(),
-        // but we actually do, for IE and Safari. Gar.
-
-        $html = sprintf('<script type="text/javascript">
-                            window.onload = function () {
-                                FB_RequireFeatures(
-                                    ["XFBML"],
-                                        function() {
-                                            FB.Facebook.init("%s", "../xd_receiver.html");
-                                        }
-                                    ); }
-
-                            function goto_login() {
-                                window.location = "%s";
-                            }
-
-                            function goto_logout() {
-                                window.location = "%s";
-                            }
-                          </script>', $apikey,
-                              $login_url, $logout_url);
-
-        $action->raw($html);
+        if ($this->requiresFB($action)) {
+
+            $apikey = common_config('facebook', 'apikey');
+            $plugin_path = common_path('plugins/FBConnect');
+
+            $login_url = common_local_url('FBConnectAuth');
+            $logout_url = common_local_url('logout');
+
+            // XXX: Facebook says we don't need this FB_RequireFeatures(),
+            // but we actually do, for IE and Safari. Gar.
+
+            $html = sprintf('<script type="text/javascript">
+                                window.onload = function () {
+                                    FB_RequireFeatures(
+                                        ["XFBML"],
+                                            function() {
+                                                FB.Facebook.init("%s", "../xd_receiver.html");
+                                            }
+                                        ); }
+
+                                function goto_login() {
+                                    window.location = "%s";
+                                }
+
+                                function goto_logout() {
+                                    window.location = "%s";
+                                }
+                              </script>', $apikey,
+                                  $login_url, $logout_url);
+
+            $action->raw($html);
+        }
+
     }
 
     // Note: this script needs to appear as close as possible to </body>
 
     function onEndShowFooter($action)
     {
+        if ($this->requiresFB($action)) {
 
-        $action->element('script',
-            array('type' => 'text/javascript',
-                  'src'  => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php'),
-                  '');
+            $action->element('script',
+                array('type' => 'text/javascript',
+                      'src'  => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php'),
+                      '');
+        }
     }
 
     function onEndShowLaconicaStyles($action)
     {
-        $action->element('link', array('rel' => 'stylesheet',
-            'type' => 'text/css',
-            'href' => common_path('plugins/FBConnect/FBConnectPlugin.css')));
+
+        if ($this->requiresFB($action)) {
+
+            $action->element('link', array('rel' => 'stylesheet',
+                'type' => 'text/css',
+                'href' => common_path('plugins/FBConnect/FBConnectPlugin.css')));
+        }
     }
 
-    function onStartPrimaryNav($action)
+    /**
+     * Does the Action we're plugged into require the FB Scripts?  We only
+     * want to output FB namespace, scripts, CSS, etc. on the pages that
+     * really need them.
+     *
+     * @param Action the action in question
+     *
+     * @return boolean true
+     */
+
+    function requiresFB($action) {
+
+        // If you're logged in w/FB Connect, you always need the FB stuff
+
+        $fbuid = $this->loggedIn();
+
+        if (!empty($fbuid)) {
+            return true;
+        }
+
+        // List of actions that require FB stuff
+
+        $needy = array('FBConnectLoginAction',
+                       'FBConnectauthAction',
+                       'FBConnectSettingsAction');
+
+        if (in_array(get_class($action), $needy)) {
+            return true;
+        }
+
+        return false;
+
+    }
+
+    /**
+     * Is the user currently logged in with FB Connect?
+     *
+     * @return mixed $fbuid the Facebook ID of the logged in user, or null
+     */
+
+    function loggedIn()
     {
         $user = common_current_user();
 
-        if ($user) {
+        if (!empty($user)) {
 
             $flink = Foreign_link::getByUserId($user->id,
                 FACEBOOK_CONNECT_SERVICE);
             $fbuid = 0;
 
-            if ($flink) {
+            if (!empty($flink)) {
 
                 try {
 
@@ -170,23 +228,38 @@ class FBConnectPlugin extends Plugin
                             $e->getMessage());
                 }
 
-                // Display Facebook Logged in indicator w/Facebook favicon
-
                 if ($fbuid > 0) {
+                    return $fbuid;
+                }
+            }
+        }
 
-                    $action->elementStart('li', array('id' => 'nav_fb'));
-                    $action->elementStart('fb:profile-pic', array('uid' => $flink->foreign_id,
-                        'linked' => 'false',
-                        'width' => 16,
-                        'height' => 16));
-                    $action->elementEnd('fb:profile-pic');
+        return null;
+    }
 
-                    $iconurl =  common_path('/plugins/FBConnect/fbfavicon.ico');
-                    $action->element('img', array('src' => $iconurl));
+    function onStartPrimaryNav($action)
+    {
 
-                    $action->elementEnd('li');
+        $user = common_current_user();
+
+        if (!empty($user)) {
+
+            $fbuid = $this->loggedIn();
+
+            if (!empty($fbuid)) {
+
+                $action->elementStart('li', array('id' => 'nav_fb'));
+                $action->elementStart('fb:profile-pic', array('uid' => $fbuid,
+                    'linked' => 'false',
+                    'width' => 16,
+                    'height' => 16));
+                $action->elementEnd('fb:profile-pic');
+
+                $iconurl =  common_path('/plugins/FBConnect/fbfavicon.ico');
+                $action->element('img', array('src' => $iconurl));
+
+                $action->elementEnd('li');
 
-                }
             }
 
             $action->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
@@ -200,14 +273,16 @@ class FBConnectPlugin extends Plugin
              $action->menuItem(common_local_url('smssettings'),
                  _('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
             }
-            $action->menuItem(common_local_url('invite'),
-                _('Invite'),
-                sprintf(_('Invite friends and colleagues to join you on %s'),
-                common_config('site', 'name')),
-                false, 'nav_invitecontact');
+            if (common_config('invite', 'enabled')) {
+                $action->menuItem(common_local_url('invite'),
+                    _('Invite'),
+                    sprintf(_('Invite friends and colleagues to join you on %s'),
+                    common_config('site', 'name')),
+                    false, 'nav_invitecontact');
+            }
 
             // Need to override the Logout link to make it do FB stuff
-            if ($flink && $fbuid > 0) {
+            if (!empty($fbuid)) {
 
                 $logout_url = common_local_url('logout');
                 $title =  _('Logout from the site');
@@ -256,7 +331,7 @@ class FBConnectPlugin extends Plugin
             return false;
         }
 
-        $connect_actions = array('SmssettingsAction',
+        $connect_actions = array('SmssettingsAction', 'ImsettingsAction',
             'TwittersettingsAction', 'FBConnectSettingsAction');
 
         if (in_array($action_name, $connect_actions)) {
@@ -270,23 +345,13 @@ class FBConnectPlugin extends Plugin
 
     function onStartLogout($action)
     {
-        $user = common_current_user();
-
-        $flink = Foreign_link::getByUserId($user->id, FACEBOOK_CONNECT_SERVICE);
-
         $action->logout();
+        $fbuid = $this->loggedIn();
 
-        if ($flink) {
-
-            $facebook = getFacebook();
-
+        if (!empty($fbuid)) {
             try {
-                $fbuid = $facebook->get_loggedin_user();
-
-                if ($fbuid > 0) {
-                    $facebook->logout(common_local_url('public'));
-                }
-
+                $facebook = getFacebook();
+                $facebook->expire_session();
             } catch (Exception $e) {
                 common_log(LOG_WARNING, 'Could\'t logout of Facebook: ' .
                     $e->getMessage());
index 4a7757fb98f13e43c47bf55cdd0841da848304fd..3b6ef60987185560c280d7554a4d609e41d49ebd 100644 (file)
@@ -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;
+}
index 2cfa422e659f859806c7cdea78fba016963062ad..0be0b4bac583df8f06d2ceadd0a6f2f947316fc6 100755 (executable)
@@ -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/showcache.php b/scripts/showcache.php
new file mode 100644 (file)
index 0000000..7a88fdb
--- /dev/null
@@ -0,0 +1,71 @@
+#!/usr/bin/env php
+<?php
+/*
+ * Laconica - a distributed open-source microblogging tool
+ * Copyright (C) 2009, Control Yourself, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+
+$shortoptions = "t:c:v:k:";
+
+$helptext = <<<ENDOFHELP
+USAGE: showcache.php <args>
+shows the cached object based on the args
+
+  -t table     Table to look up
+  -c column    Column to look up, default "id"
+  -v value     Value to look up
+  -k key       Key to look up; other args are ignored
+
+ENDOFHELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+$karg = get_option_value('k');
+
+if (!empty($karg)) {
+    $k = common_cache_key($karg);
+} else {
+    $table = get_option_value('t');
+    if (empty($table)) {
+        die("No table or key specified\n");
+    }
+    $column = get_option_value('c');
+    if (empty($column)) {
+        $column = 'id';
+    }
+    $value = get_option_value('v');
+
+    $k = Memcached_DataObject::cacheKey($table, $column, $value);
+}
+
+print "Checking key '$k'...\n";
+
+$c = common_memcache();
+
+if (empty($c)) {
+    die("Can't initialize cache object!\n");
+}
+
+$obj = $c->get($k);
+
+if (empty($obj)) {
+    print "Empty.\n";
+} else {
+    var_dump($obj);
+    print "\n";
+}
index 5ffdda58fafb8fdcd2ad643bfa1ca4bd918d1a3c..8b10bfbadda5c5396f82c38c923da5a0526288ec 100755 (executable)
@@ -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();
 
index 3eecfec29a13725aa46684428b30dc1d301b3052..ca62181203a6952167e33e4c690318e59c582d42 100755 (executable)
 
 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();
index 78fcd7ecefcca0187e3a620f6dcd6eb8c4cf4d91..69d1bec590c15e832d082211862c0fadd1a41fa0 100644 (file)
@@ -206,7 +206,10 @@ border-radius:4px;
 padding:0 7px;
 }
 
-
+.form_settings input.form_action-default {
+margin-right:11px;
+}
+.form_settings input.form_action-default,
 .form_settings input.form_action-primary {
 padding:0;
 }
@@ -270,7 +273,6 @@ clear:both;
 margin-bottom:18px;
 }
 
-
 #anon_notice {
 float:left;
 width:43.2%;
@@ -285,7 +287,6 @@ font-size:1.1em;
 font-weight:bold;
 }
 
-
 #footer {
 float:left;
 width:64%;
@@ -588,16 +589,16 @@ font-weight:normal;
 content: ")";
 font-weight:normal;
 }
-
-.entity_profile dt {
-display:none;
-}
+.entity_profile dt,
 .entity_profile h2 {
 display:none;
 }
+.entity_profile .role {
+margin-left:11px;
+font-style:italic;
+}
 /* entity_profile */
 
-
 /*entity_actions*/
 .entity_actions {
 float:right;
@@ -726,7 +727,6 @@ margin-bottom:0;
 min-height:60px;
 }
 
-
 .profile .form_group_join legend,
 .profile .form_group_leave legend,
 .profile .form_user_subscribe legend,
@@ -761,13 +761,11 @@ display:inline;
 margin-right:11px;
 }
 
-
 .profile .entity_profile .form_subscription_edit label {
 font-weight:normal;
 margin-right:11px;
 }
 
-
 /* NOTICE */
 .notice,
 .profile {
@@ -790,7 +788,6 @@ width:95%;
 float:left;
 }
 
-
 /* NOTICES */
 #notices_primary {
 float:left;
@@ -962,7 +959,6 @@ border:0;
 padding:0;
 }
 
-
 .notice .attachment {
 position:relative;
 padding-left:16px;
@@ -1031,7 +1027,9 @@ border-radius:7px;
 -moz-border-radius:7px;
 -webkit-border-radius:7px;
 }
-
+#jOverlayContent #content img {
+max-width:480px;
+}
 #attachment_view #oembed_info {
 margin-top:11px;
 }
@@ -1059,7 +1057,6 @@ margin-bottom:18px;
 padding-left:20px;
 }
 
-
 #filter_tags {
 margin-bottom:11px;
 float:left;
@@ -1105,8 +1102,6 @@ top:3px;
 left:3px;
 }
 
-
-
 .pagination {
 float:left;
 clear:both;
@@ -1152,7 +1147,6 @@ padding-right:30px;
 }
 /* END: NOTICE */
 
-
 .hentry .entry-content p {
 margin-bottom:18px;
 }
@@ -1169,7 +1163,6 @@ margin-bottom:18px;
 margin-left:18px;
 }
 
-
 /* TOP_POSTERS */
 .section tbody td {
 padding-right:18px;
@@ -1197,7 +1190,6 @@ margin-right:0;
 display:none;
 }
 
-
 /* tagcloud */
 .tag-cloud {
 list-style-type:none;
@@ -1280,6 +1272,10 @@ clear:both;
 margin-bottom:0;
 }
 
+#form_settings_design #settings_design_background-image img {
+max-width:480px;
+}
+
 #form_settings_design #settings_design_color .form_data,
 #form_settings_design #color-picker {
 float:left;