]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge branch '0.7.x' into 0.8.x
authorEvan Prodromou <evan@controlyourself.ca>
Mon, 8 Jun 2009 18:55:32 +0000 (11:55 -0700)
committerEvan Prodromou <evan@controlyourself.ca>
Mon, 8 Jun 2009 18:55:32 +0000 (11:55 -0700)
Conflicts:
classes/Notice.php
classes/Profile.php
lib/common.php
lib/util.php
scripts/getvaliddaemons.php
scripts/stopdaemons.sh

26 files changed:
README
actions/api.php
actions/shownotice.php
actions/twitapiaccount.php
actions/twitapidirect_messages.php
actions/twitapistatuses.php
actions/twitapiusers.php
classes/Fave.php
classes/Memcached_DataObject.php
classes/Notice.php
classes/Notice_inbox.php
classes/Notice_tag.php
classes/Profile.php
classes/Reply.php
classes/User.php
classes/User_group.php
db/notice_source.sql
lib/mail.php
lib/omb.php
lib/twitterapi.php
lib/util.php
scripts/fixup_utf8.php
scripts/getvaliddaemons.php
scripts/inboxqueuehandler.php [deleted file]
scripts/memcachedqueuehandler.php [deleted file]
scripts/stopdaemons.sh

diff --git a/README b/README
index 9cbe84f0e51bfc68244314c8ac39dc5530802e18..2099f94d62f46f953bd13716ef9b3abc0d98cd00 100644 (file)
--- a/README
+++ b/README
@@ -2,8 +2,8 @@
 README
 ------
 
-Laconica 0.7.3 ("You Are The Everything")
-7 April 2009
+Laconica 0.7.4 ("Can't Get There From Here")
+29 May 2009
 
 This is the README file for Laconica, the Open Source microblogging
 platform. It includes installation instructions, descriptions of
@@ -71,29 +71,29 @@ for additional terms.
 New this version
 ================
 
-This is a minor bug-fix and feature release since version 0.7.2.1,
-released Mar 11 2009. Notable changes this version:
-
-- A plugin to allow a templating language for customization
-- A plugin for Piwik Analytics engine
-- A bookmarklet for posting a notice about a Web page you're reading
-- A welcome notice ('welcomebot') and default subscription for new users
-- Support for SSL for some or all pages on the site
-- Better handling of empty notice lists on many pages
-- Major improvements to the Twitter friend-sync offline processing
-- subscribers, subscriptions, groups are listed on the Personal page.
-- "Invite" link restored to main menu
-- Better memory handling in FOAF output
-- Fix for SUP support (FriendFeed)
-- Correct and intelligent redirect HTTP status codes
-- Fix DB collations for search and sort
-- Better H1s and Titles using user full names
-- Fixes to make the linkback plugin operational
-- Better indication that a notice is being published by Ajax (spinner)
-- Better and unified Atom output
-- Hiding "register" and "join now" messages when site is closed
-- ping, twitter and facebook queuehandlers working better
-- Updated RPM spec
+This is a minor bug-fix and feature release since version 0.7.3,
+released Apr 4 2009. Notable changes this version:
+
+- Improved handling of UTF-8 characters. The new code is *not* backwards
+  compatible by default; see "Upgrading" below for instructions on
+  converting existing databases to the correct character set.
+- Unroll joins for large queries. This greatly enhanced database
+  performance -- up to 50x for some queries -- at the expense of making
+  an extra DB hit for some queries.
+- Added an optional plugin to use WikiHashtags
+  (http://hashtags.wikia.com/) for the sidebar on hashtag pages.
+- Optimized Twitter friend synchronization.
+- Better error handling for Ajax posting of notices, including
+  HTTP errors and timeouts.
+- Experimental Comet plugin -- supports the cometd and the Bayeux
+  protocol. Using this plugin, you can show "real time" updates on the
+  public and tag pages. However, server configuration is complex.
+- If queues are enabled, update inboxes and memcached off-line. Speeds
+  up posting considerably.
+- Correctly shorten links posted through XMPP.
+- <link> elements for pagination, supported by some browsers like Opera.
+- Corrected date format in search API.
+- Made the public XRDS file work correctly.
 
 Prerequisites
 =============
@@ -197,9 +197,9 @@ especially if you've previously installed PHP/MySQL packages.
 1. Unpack the tarball you downloaded on your Web server. Usually a
    command like this will work:
 
-          tar zxf laconica-0.7.3.tar.gz
+          tar zxf laconica-0.7.4.tar.gz
 
-   ...which will make a laconica-0.7.3 subdirectory in your current
+   ...which will make a laconica-0.7.4 subdirectory in your current
    directory. (If you don't have shell access on your Web server, you
    may have to unpack the tarball on your local computer and FTP the
    files to the server.)
@@ -207,7 +207,7 @@ especially if you've previously installed PHP/MySQL packages.
 2. Move the tarball to a directory of your choosing in your Web root
    directory. Usually something like this will work:
 
-          mv laconica-0.7.3 /var/www/mublog
+          mv laconica-0.7.4 /var/www/mublog
 
    This will make your Laconica instance available in the mublog path of
    your server, like "http://example.net/mublog". "microblog" or
@@ -704,7 +704,7 @@ with this situation.
 If you've been using Laconica 0.6, 0.5 or lower, or if you've been
 tracking the "git" version of the software, you will probably want
 to upgrade and keep your existing data. There is no automated upgrade
-procedure in Laconica 0.7.3. Try these step-by-step instructions; read
+procedure in Laconica 0.7.4. Try these step-by-step instructions; read
 to the end first before trying them.
 
 0. Download Laconica and set up all the prerequisites as if you were
@@ -1239,7 +1239,7 @@ repository (see below), and you get a compilation error ("unexpected
 T_STRING") in the browser, check to see that you don't have any
 conflicts in your code.
 
-If you upgraded to Laconica 0.7.3 without reading the "Notice inboxes"
+If you upgraded to Laconica 0.7.4 without reading the "Notice inboxes"
 section above, and all your users' 'Personal' tabs are empty, read the
 "Notice inboxes" section above.
 
@@ -1330,6 +1330,8 @@ if anyone's been overlooked in error.
 * Ken Sedgwick
 * Brian Hendrickson
 * Tobias Diekershoff
+* Dan Moore
+* Fil
 
 Thanks also to the developers of our upstream library code and to the
 thousands of people who have tried out Identi.ca, installed Laconi.ca,
index b25ba99f30cfcf44b56f6a477856b9c1c82e675c..b8da852b536d469682f6fcee277894247696695e 100644 (file)
@@ -144,8 +144,8 @@ class ApiAction extends Action
         }
 
         if (in_array($fullname, $bareauth)) {
-            # bareauth: only needs auth if without an argument
-            if ($this->api_arg) {
+            # bareauth: only needs auth if without an argument or query param specifying user
+            if ($this->api_arg || $this->arg('id') || is_numeric($this->arg('user_id')) || $this->arg('screen_name')) {
                 return false;
             } else {
                 return true;
index 34c8a8e9464c68e21c47a45ca52467b6b8b3b3d5..b0d973a991cad8e61cfa2d8ce632013e89f3201b 100644 (file)
@@ -122,7 +122,7 @@ class ShownoticeAction extends Action
 
     function lastModified()
     {
-        return max(strtotime($this->notice->created),
+        return max(strtotime($this->notice->modified),
                    strtotime($this->profile->modified),
                    ($this->avatar) ? strtotime($this->avatar->modified) : 0);
     }
index 68a18cb57b43c87d7a9e4e6090f5b5b1df019a9a..8b956f897a397606434d2a2d1040a71c31b937c8 100644 (file)
@@ -98,9 +98,31 @@ class TwitapiaccountAction extends TwitterapiAction
         $this->serverError(_('API method under construction.'), $code=501);
     }
 
+    // We don't have a rate limit, but some clients check this method.
+    // It always returns the same thing: 100 hit left.
     function rate_limit_status($args, $apidata)
     {
         parent::handle($args);
-        $this->serverError(_('API method under construction.'), $code=501);
+
+        $type = $apidata['content-type'];
+        $this->init_document($type);
+
+        if ($apidata['content-type'] == 'xml') {
+            $this->elementStart('hash');
+            $this->element('remaining-hits', array('type' => 'integer'), 100);
+            $this->element('hourly-limit', array('type' => 'integer'), 100);
+            $this->element('reset-time', array('type' => 'datetime'), null);
+            $this->element('reset_time_in_seconds', array('type' => 'integer'), 0);
+            $this->elementEnd('hash');
+        } elseif ($apidata['content-type'] == 'json') {
+
+            $out = array('reset_time_in_seconds' => 0,
+                         'remaining_hits' => 100,
+                         'hourly_limit' => 100,
+                         'reset_time' => '');
+            print json_encode($out);
+        }
+
+        $this->end_document($type);
     }
 }
index 7101db8df585354462150a1eae3e98364ca2b96a..d2dbdb619b180044a0388cd592382944eec4018a 100644 (file)
@@ -43,7 +43,7 @@ class Twitapidirect_messagesAction extends TwitterapiAction
         $count = $this->arg('count');
         $since = $this->arg('since');
         $since_id = $this->arg('since_id');
-        $before_id = $this->arg('before_id');
+        $max_id = $this->arg('max_id');
 
         $page = $this->arg('page');
 
@@ -74,8 +74,8 @@ class Twitapidirect_messagesAction extends TwitterapiAction
             $link = $server . $user->nickname . '/outbox';
         }
 
-        if ($before_id) {
-            $message->whereAdd("id < $before_id");
+        if ($max_id) {
+            $message->whereAdd("id <= $max_id");
         }
 
         if ($since_id) {
index 3abeba36727d2f8ae4ee6708f8d3aab95d00a64d..1fbde6639f3bf32b4be7131e8a28554e1acdcb5a 100644 (file)
@@ -45,22 +45,21 @@ class TwitapistatusesAction extends TwitterapiAction
 
         $page = $this->arg('page');
         $since_id = $this->arg('since_id');
-        $before_id = $this->arg('before_id');
+        $max_id = $this->arg('max_id');
 
-        // NOTE: page, since_id, and before_id are extensions to Twitter API -- TB
         if (!$page) {
             $page = 1;
         }
         if (!$since_id) {
             $since_id = 0;
         }
-        if (!$before_id) {
-            $before_id = 0;
+        if (!$max_id) {
+            $max_id = 0;
         }
 
         $since = strtotime($this->arg('since'));
 
-        $notice = Notice::publicStream((($page-1)*$MAX_PUBSTATUSES), $MAX_PUBSTATUSES, $since_id, $before_id, $since);
+        $notice = Notice::publicStream((($page-1)*$MAX_PUBSTATUSES), $MAX_PUBSTATUSES, $since_id, $max_id, $since);
 
         if ($notice) {
 
@@ -97,7 +96,7 @@ class TwitapistatusesAction extends TwitterapiAction
         $since_id = $this->arg('since_id');
         $count = $this->arg('count');
         $page = $this->arg('page');
-        $before_id = $this->arg('before_id');
+        $max_id = $this->arg('max_id');
 
         if (!$page) {
             $page = 1;
@@ -111,9 +110,8 @@ class TwitapistatusesAction extends TwitterapiAction
             $since_id = 0;
         }
 
-        // NOTE: before_id is an extension to Twitter API -- TB
-        if (!$before_id) {
-            $before_id = 0;
+        if (!$max_id) {
+            $max_id = 0;
         }
 
         $since = strtotime($this->arg('since'));
@@ -133,7 +131,7 @@ class TwitapistatusesAction extends TwitterapiAction
         $link = common_local_url('all', array('nickname' => $user->nickname));
         $subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), $user->nickname, $sitename);
 
-        $notice = $user->noticesWithFriends(($page-1)*20, $count, $since_id, $before_id, $since);
+        $notice = $user->noticesWithFriends(($page-1)*20, $count, $since_id, $max_id, $since);
 
         switch($apidata['content-type']) {
          case 'xml':
@@ -184,7 +182,7 @@ class TwitapistatusesAction extends TwitterapiAction
         $since = $this->arg('since');
         $since_id = $this->arg('since_id');
         $page = $this->arg('page');
-        $before_id = $this->arg('before_id');
+        $max_id = $this->arg('max_id');
 
         if (!$page) {
             $page = 1;
@@ -198,9 +196,8 @@ class TwitapistatusesAction extends TwitterapiAction
             $since_id = 0;
         }
 
-        // NOTE: before_id is an extensions to Twitter API -- TB
-        if (!$before_id) {
-            $before_id = 0;
+        if (!$max_id) {
+            $max_id = 0;
         }
 
         $since = strtotime($this->arg('since'));
@@ -220,7 +217,7 @@ class TwitapistatusesAction extends TwitterapiAction
 
         # XXX: since
 
-        $notice = $user->getNotices((($page-1)*20), $count, $since_id, $before_id, $since);
+        $notice = $user->getNotices((($page-1)*20), $count, $since_id, $max_id, $since);
 
         switch($apidata['content-type']) {
          case 'xml':
@@ -353,7 +350,7 @@ class TwitapistatusesAction extends TwitterapiAction
         $count = $this->arg('count');
         $page = $this->arg('page');
         $since_id = $this->arg('since_id');
-        $before_id = $this->arg('before_id');
+        $max_id = $this->arg('max_id');
 
         $user = $this->get_user($apidata['api_arg'], $apidata);
         $this->auth_user = $apidata['user'];
@@ -380,15 +377,14 @@ class TwitapistatusesAction extends TwitterapiAction
             $since_id = 0;
         }
 
-        // NOTE: before_id is an extension to Twitter API -- TB
-        if (!$before_id) {
-            $before_id = 0;
+        if (!$max_id) {
+            $max_id = 0;
         }
 
         $since = strtotime($this->arg('since'));
 
         $notice = $user->getReplies((($page-1)*20),
-            $count, $since_id, $before_id, $since);
+            $count, $since_id, $max_id, $since);
         $notices = array();
 
         while ($notice->fetch()) {
index 1542cfb33e3d064130093272e014ac4fa6262d81..b90bbfa985c9a6a381a5397647b54518225e6768 100644 (file)
@@ -25,110 +25,61 @@ class TwitapiusersAction extends TwitterapiAction
 {
 
     function show($args, $apidata)
-    {        
+    {
         parent::handle($args);
 
-        if (!in_array($apidata['content-type'], array('xml', 'json'))) {            
+        if (!in_array($apidata['content-type'], array('xml', 'json'))) {
             $this->clientError(_('API method not found!'), $code = 404);
             return;
         }
-                
-               $user = null;
-               $email = $this->arg('email');
-               $user_id = $this->arg('user_id');
-
-               if ($email) {
-                       $user = User::staticGet('email', $email);
-               } elseif ($user_id) {
-                       $user = $this->get_user($user_id);  
-               } elseif (isset($apidata['api_arg'])) {
-                       $user = $this->get_user($apidata['api_arg']);
-           } elseif (isset($apidata['user'])) {
-               $user = $apidata['user'];
-           }
-       
-               if (!$user) {               
-                       // XXX: Twitter returns a random(?) user instead of throwing and err! -- Zach
-                       $this->client_error(_('Not found.'), 404, $apidata['content-type']);
-                       return;
-               }
-
-               $profile = $user->getProfile();
-
-               if (!$profile) {
-                       common_server_error(_('User has no profile.'));
-                       return;
-               }
-
-               $twitter_user = $this->twitter_user_array($profile, true);
-
-               // Add in extended user fields offered up by this method
-               $twitter_user['created_at'] = $this->date_twitter($profile->created);
-
-               $subbed = DB_DataObject::factory('subscription');
-               $subbed->subscriber = $profile->id;
-               $subbed_count = (int) $subbed->count() - 1;
-
-               $notices = DB_DataObject::factory('notice');
-               $notices->profile_id = $profile->id;
-               $notice_count = (int) $notices->count();
-
-               $twitter_user['friends_count'] = (is_int($subbed_count)) ? $subbed_count : 0;
-               $twitter_user['statuses_count'] = (is_int($notice_count)) ? $notice_count : 0;
-
-               // Other fields Twitter sends...
-               $twitter_user['profile_background_color'] = '';
-               $twitter_user['profile_background_image_url'] = '';
-               $twitter_user['profile_text_color'] = '';
-               $twitter_user['profile_link_color'] = '';
-               $twitter_user['profile_sidebar_fill_color'] = '';
-               $twitter_user['profile_sidebar_border_color'] = '';
-               $twitter_user['profile_background_tile'] = false;
-
-               $faves = DB_DataObject::factory('fave');
-               $faves->user_id = $user->id;
-               $faves_count = (int) $faves->count();
-               $twitter_user['favourites_count'] = $faves_count;
-
-               $timezone = 'UTC';
-
-               if ($user->timezone) {
-                       $timezone = $user->timezone;
-               }
-
-               $t = new DateTime;
-               $t->setTimezone(new DateTimeZone($timezone));
-               $twitter_user['utc_offset'] = $t->format('Z');
-               $twitter_user['time_zone'] = $timezone;
-
-               if (isset($apidata['user'])) {
-
-                       $twitter_user['following'] = $apidata['user']->isSubscribed($profile);
-            
-                       // Notifications on?
-                       $sub = Subscription::pkeyGet(array('subscriber' =>
-                               $apidata['user']->id, 'subscribed' => $profile->id));
-            
-                       if ($sub) {
-                               $twitter_user['notifications'] = ($sub->jabber || $sub->sms);
-                       }
-               }
-        
-               if ($apidata['content-type'] == 'xml') {
-                       $this->init_document('xml');
-                       $this->show_twitter_xml_user($twitter_user);
-                       $this->end_document('xml');
-               } elseif ($apidata['content-type'] == 'json') {
-                       $this->init_document('json');
-                       $this->show_json_objects($twitter_user);
-                       $this->end_document('json');
-               } else {
-                   
-                   // This is in case 'show' was called via /account/verify_credentials
-                   // without a format (xml or json).
+
+        $user = null;
+        $email = $this->arg('email');
+        $user_id = $this->arg('user_id');
+
+        // XXX: email field deprecated in Twitter's API
+
+        // XXX: Also: need to add screen_name param
+
+        if ($email) {
+            $user = User::staticGet('email', $email);
+        } elseif ($user_id) {
+            $user = $this->get_user($user_id);
+        } elseif (isset($apidata['api_arg'])) {
+            $user = $this->get_user($apidata['api_arg']);
+        } elseif (isset($apidata['user'])) {
+            $user = $apidata['user'];
+        }
+
+        if (!$user) {
+            $this->client_error(_('Not found.'), 404, $apidata['content-type']);
+            return;
+        }
+
+        $profile = $user->getProfile();
+
+        if (!$profile) {
+            common_server_error(_('User has no profile.'));
+            return;
+        }
+
+        $twitter_user = $this->twitter_user_array($profile, true);
+
+        if ($apidata['content-type'] == 'xml') {
+            $this->init_document('xml');
+            $this->show_twitter_xml_user($twitter_user);
+            $this->end_document('xml');
+        } elseif ($apidata['content-type'] == 'json') {
+            $this->init_document('json');
+            $this->show_json_objects($twitter_user);
+            $this->end_document('json');
+        } else {
+
+            // This is in case 'show' was called via /account/verify_credentials
+            // without a format (xml or json).
             header('Content-Type: text/html; charset=utf-8');
             print 'Authorized';
         }
 
-       }
+    }
 }
index 915b4572ffed5dd11e533a664c55e4d687d725b3..572334ce4f8cf17e8811cf0eab51cd77ed922549 100644 (file)
@@ -46,7 +46,7 @@ class Fave extends Memcached_DataObject
         return $ids;
     }
 
-    function _streamDirect($user_id, $offset, $limit, $since_id, $before_id, $since)
+    function _streamDirect($user_id, $offset, $limit, $since_id, $max_id, $since)
     {
         $fav = new Fave();
 
@@ -59,8 +59,8 @@ class Fave extends Memcached_DataObject
             $fav->whereAdd('notice_id > ' . $since_id);
         }
 
-        if ($before_id != 0) {
-            $fav->whereAdd('notice_id < ' . $before_id);
+        if ($max_id != 0) {
+            $fav->whereAdd('notice_id <= ' . $max_id);
         }
 
         if (!is_null($since)) {
index 52ad4100fcec32cc3a823172b269556fdab32a06..33ac70dd045643a5a57ff87e58d383a0bc52bd2b 100644 (file)
@@ -239,8 +239,14 @@ class Memcached_DataObject extends DB_DataObject
         $result = parent::_connect();
         if (!$exists) {
             $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
-            if (common_config('db', 'utf8')) {
-                $DB->query('SET NAMES "utf8"');
+            if (common_config('db', 'type') == 'mysql' &&
+                common_config('db', 'utf8')) {
+                $conn = $DB->connection;
+                if ($DB instanceof DB_mysqli) {
+                    mysqli_set_charset($conn, 'utf8');
+                } else if ($DB instanceof DB_mysql) {
+                    mysql_set_charset('utf8', $conn);
+                }
             }
         }
         return $result;
index 1b5c0ab0a55afdc53592b860ec71ca414fa615a5..ca67306df1a7d7d025a57c24e8eb9923e5b56b23 100644 (file)
@@ -124,6 +124,8 @@ class Notice extends Memcached_DataObject
 
         $profile = Profile::staticGet($profile_id);
 
+        $final =  common_shorten_links($content);
+
         if (!$profile) {
             common_log(LOG_ERR, 'Problem saving notice. Unknown user.');
             return _('Problem saving notice. Unknown user.');
@@ -134,7 +136,7 @@ class Notice extends Memcached_DataObject
             return _('Too many notices too fast; take a breather and post again in a few minutes.');
         }
 
-        if (common_config('site', 'dupelimit') > 0 && !Notice::checkDupes($profile_id, $content)) {
+        if (common_config('site', 'dupelimit') > 0 && !Notice::checkDupes($profile_id, $final)) {
             common_log(LOG_WARNING, 'Dupe posting by profile #' . $profile_id . '; throttled.');
                        return _('Too many duplicate messages too quickly; take a breather and post again in a few minutes.');
         }
@@ -165,8 +167,8 @@ class Notice extends Memcached_DataObject
 
                $notice->reply_to = $reply_to;
                $notice->created = common_sql_now();
-               $notice->content = $content;
-               $notice->rendered = common_render_content($content, $notice);
+               $notice->content = $final;
+               $notice->rendered = common_render_content($final, $notice);
                $notice->source = $source;
                $notice->uri = $uri;
 
@@ -202,13 +204,9 @@ class Notice extends Memcached_DataObject
 
             $notice->saveReplies();
             $notice->saveTags();
-            $notice->saveGroups();
 
-            if (common_config('queue', 'enabled')) {
-                $notice->addToAuthorInbox();
-            } else {
-                $notice->addToInboxes();
-            }
+            $notice->addToInboxes();
+            $notice->saveGroups();
 
             $notice->query('COMMIT');
 
@@ -218,13 +216,7 @@ class Notice extends Memcached_DataObject
         # Clear the cache for subscribed users, so they'll update at next request
         # XXX: someone clever could prepend instead of clearing the cache
 
-        if (common_config('memcached', 'enabled')) {
-            if (common_config('queue', 'enabled')) {
-                $notice->blowAuthorCaches();
-            } else {
-                $notice->blowCaches();
-            }
-        }
+        $notice->blowCaches();
 
         return $notice;
     }
@@ -297,17 +289,6 @@ class Notice extends Memcached_DataObject
         $this->blowGroupCache($blowLast);
     }
 
-    function blowAuthorCaches($blowLast=false)
-    {
-        // Clear the user's cache
-        $cache = common_memcache();
-        if (!empty($cache)) {
-            $cache->delete(common_cache_key('notice_inbox:by_user:'.$this->profile_id));
-        }
-        $this->blowNoticeCache($blowLast);
-        $this->blowPublicCache($blowLast);
-    }
-
     function blowGroupCache($blowLast=false)
     {
         $cache = common_memcache();
@@ -443,22 +424,22 @@ class Notice extends Memcached_DataObject
     # XXX: too many args; we need to move to named params or even a separate
     # class for notice streams
 
-    static function getStream($qry, $cachekey, $offset=0, $limit=20, $since_id=0, $before_id=0, $order=null, $since=null) {
+    static function getStream($qry, $cachekey, $offset=0, $limit=20, $since_id=0, $max_id=0, $order=null, $since=null) {
 
         if (common_config('memcached', 'enabled')) {
 
-            # Skip the cache if this is a since, since_id or before_id qry
-            if ($since_id > 0 || $before_id > 0 || $since) {
-                return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since);
+            # Skip the cache if this is a since, since_id or max_id qry
+            if ($since_id > 0 || $max_id > 0 || $since) {
+                return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since);
             } else {
                 return Notice::getCachedStream($qry, $cachekey, $offset, $limit, $order);
             }
         }
 
-        return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since);
+        return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since);
     }
 
-    static function getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since) {
+    static function getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since) {
 
         $needAnd = false;
         $needWhere = true;
@@ -480,7 +461,7 @@ class Notice extends Memcached_DataObject
             $qry .= ' notice.id > ' . $since_id;
         }
 
-        if ($before_id > 0) {
+        if ($max_id > 0) {
 
             if ($needWhere) {
                 $qry .= ' WHERE ';
@@ -489,7 +470,7 @@ class Notice extends Memcached_DataObject
                 $qry .= ' AND ';
             }
 
-            $qry .= ' notice.id < ' . $before_id;
+            $qry .= ' notice.id <= ' . $max_id;
         }
 
         if ($since) {
@@ -647,17 +628,17 @@ class Notice extends Memcached_DataObject
         }
     }
 
-    function publicStream($offset=0, $limit=20, $since_id=0, $before_id=0, $since=null)
+    function publicStream($offset=0, $limit=20, $since_id=0, $max_id=0, $since=null)
     {
         $ids = Notice::stream(array('Notice', '_publicStreamDirect'),
                               array(),
                               'public',
-                              $offset, $limit, $since_id, $before_id, $since);
+                              $offset, $limit, $since_id, $max_id, $since);
 
         return Notice::getStreamByIds($ids);
     }
 
-    function _publicStreamDirect($offset=0, $limit=20, $since_id=0, $before_id=0, $since=null)
+    function _publicStreamDirect($offset=0, $limit=20, $since_id=0, $max_id=0, $since=null)
     {
         $notice = new Notice();
 
@@ -681,8 +662,8 @@ class Notice extends Memcached_DataObject
             $notice->whereAdd('id > ' . $since_id);
         }
 
-        if ($before_id != 0) {
-            $notice->whereAdd('id < ' . $before_id);
+        if ($max_id != 0) {
+            $notice->whereAdd('id <= ' . $max_id);
         }
 
         if (!is_null($since)) {
@@ -726,33 +707,6 @@ class Notice extends Memcached_DataObject
         return;
     }
 
-    function addToAuthorInbox()
-    {
-        $enabled = common_config('inboxes', 'enabled');
-
-        if ($enabled === true || $enabled === 'transitional') {
-            $user = User::staticGet('id', $this->profile_id);
-            if (empty($user)) {
-                return;
-            }
-            $inbox = new Notice_inbox();
-            $UT = common_config('db','type')=='pgsql'?'"user"':'user';
-            $qry = 'INSERT INTO notice_inbox (user_id, notice_id, created) ' .
-              "SELECT $UT.id, " . $this->id . ", '" . $this->created . "' " .
-              "FROM $UT " .
-              "WHERE $UT.id = " . $this->profile_id . ' ' .
-              'AND NOT EXISTS (SELECT user_id, notice_id ' .
-              'FROM notice_inbox ' .
-              "WHERE user_id = " . $this->profile_id . ' '.
-              'AND notice_id = ' . $this->id . ' )';
-            if ($enabled === 'transitional') {
-                $qry .= " AND $UT.inboxed = 1";
-            }
-            $inbox->query($qry);
-        }
-        return;
-    }
-
     function saveGroups()
     {
         $enabled = common_config('inboxes', 'enabled');
@@ -1024,15 +978,15 @@ class Notice extends Memcached_DataObject
         }
     }
 
-    function stream($fn, $args, $cachekey, $offset=0, $limit=20, $since_id=0, $before_id=0, $since=null, $tag=null)
+    function stream($fn, $args, $cachekey, $offset=0, $limit=20, $since_id=0, $max_id=0, $since=null)
     {
         $cache = common_memcache();
 
         if (empty($cache) ||
-            $since_id != 0 || $before_id != 0 || !is_null($since) ||
+            $since_id != 0 || $max_id != 0 || (!is_null($since) && $since > 0) ||
             ($offset + $limit) > NOTICE_CACHE_WINDOW) {
             return call_user_func_array($fn, array_merge($args, array($offset, $limit, $since_id,
-                                                                      $before_id, $since, $tag)));
+                                                                      $max_id, $since)));
         }
 
         $idkey = common_cache_key($cachekey);
index dec14b0d18897cf0fcb40ddf8e44305929ca5103..8a27e174785101b9b52b6e3bf9211b3867e00ab2 100644 (file)
@@ -43,15 +43,15 @@ class Notice_inbox extends Memcached_DataObject
     /* the code above is auto generated do not remove the tag below */
     ###END_AUTOCODE
 
-    function stream($user_id, $offset, $limit, $since_id, $before_id, $since)
+    function stream($user_id, $offset, $limit, $since_id, $max_id, $since)
     {
         return Notice::stream(array('Notice_inbox', '_streamDirect'),
                               array($user_id),
                               'notice_inbox:by_user:'.$user_id,
-                              $offset, $limit, $since_id, $before_id, $since);
+                              $offset, $limit, $since_id, $max_id, $since);
     }
 
-    function _streamDirect($user_id, $offset, $limit, $since_id, $before_id, $since)
+    function _streamDirect($user_id, $offset, $limit, $since_id, $max_id, $since)
     {
         $inbox = new Notice_inbox();
 
@@ -61,8 +61,8 @@ class Notice_inbox extends Memcached_DataObject
             $inbox->whereAdd('notice_id > ' . $since_id);
         }
 
-        if ($before_id != 0) {
-            $inbox->whereAdd('notice_id < ' . $before_id);
+        if ($max_id != 0) {
+            $inbox->whereAdd('notice_id <= ' . $max_id);
         }
 
         if (!is_null($since)) {
index e5b7722430b99be54a6fe2927b13275f86f44df0..758a6659473ec491bd625758ac697090e74aa9b8 100644 (file)
@@ -46,7 +46,7 @@ class Notice_tag extends Memcached_DataObject
         return Notice::getStreamByIds($ids);
     }
 
-    function _streamDirect($tag, $offset, $limit, $since_id, $before_id, $since)
+    function _streamDirect($tag, $offset, $limit, $since_id, $max_id, $since)
     {
         $nt = new Notice_tag();
 
@@ -59,8 +59,8 @@ class Notice_tag extends Memcached_DataObject
             $nt->whereAdd('notice_id > ' . $since_id);
         }
 
-        if ($before_id != 0) {
-            $nt->whereAdd('notice_id < ' . $before_id);
+        if ($max_id != 0) {
+            $nt->whereAdd('notice_id < ' . $max_id);
         }
 
         if (!is_null($since)) {
index afc0ea4f74557b29824ef266a54be6fd59d81202..4a459b9740e4055b5a62c9349ba689b9dc9598fd 100644 (file)
@@ -170,7 +170,7 @@ class Profile extends Memcached_DataObject
         $ids = Notice::stream(array($this, '_streamDirect'),
                               array(),
                               'profile:notice_ids:' . $this->id,
-                              $offset, $limit, $since_id, $before_id, $since);
+                              $offset, $limit, $since_id, $max_id, $since);
 
         return Notice::getStreamByIds($ids);
     }
@@ -225,8 +225,8 @@ class Profile extends Memcached_DataObject
             $notice->whereAdd('id > ' . $since_id);
         }
 
-        if ($before_id != 0) {
-            $notice->whereAdd('id < ' . $before_id);
+        if ($max_id != 0) {
+            $notice->whereAdd('id <= ' . $max_id);
         }
 
         if (!is_null($since)) {
index 4439053b444934f05fb69fa9b4d5b396700f532e..49b1e05e517e1bd34bb7645cead3148990f27c0b 100644 (file)
@@ -22,16 +22,16 @@ class Reply extends Memcached_DataObject
     /* the code above is auto generated do not remove the tag below */
     ###END_AUTOCODE
 
-    function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
+    function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null)
     {
         $ids = Notice::stream(array('Reply', '_streamDirect'),
                               array($user_id),
                               'reply:stream:' . $user_id,
-                              $offset, $limit, $since_id, $before_id, $since);
+                              $offset, $limit, $since_id, $max_id, $since);
         return $ids;
     }
 
-    function _streamDirect($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
+    function _streamDirect($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null)
     {
         $reply = new Reply();
         $reply->profile_id = $user_id;
@@ -40,8 +40,8 @@ class Reply extends Memcached_DataObject
             $reply->whereAdd('notice_id > ' . $since_id);
         }
 
-        if ($before_id != 0) {
-            $reply->whereAdd('notice_id < ' . $before_id);
+        if ($max_id != 0) {
+            $reply->whereAdd('notice_id < ' . $max_id);
         }
 
         if (!is_null($since)) {
index ea8ba40817ac74c3901c9f8f519deb677f616339..08a166d5ae4a4478be5943cd69eee776834e54ec 100644 (file)
@@ -403,7 +403,6 @@ class User extends Memcached_DataObject
     function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
     {
         $ids = Reply::stream($this->id, $offset, $limit, $since_id, $before_id, $since);
-        common_debug("Ids = " . implode(',', $ids));
         return Notice::getStreamByIds($ids);
     }
 
index 7cc31e7026d0aeb693d481c1a7c820b3807f17dc..a135015baca3a1f2d67601ebb9ae6f03d4c5dd0f 100644 (file)
@@ -58,7 +58,7 @@ class User_group extends Memcached_DataObject
         return Notice::getStreamByIds($ids);
     }
 
-    function _streamDirect($offset, $limit, $since_id, $before_id, $since)
+    function _streamDirect($offset, $limit, $since_id, $max_id, $since)
     {
         $inbox = new Group_inbox();
 
@@ -71,8 +71,8 @@ class User_group extends Memcached_DataObject
             $inbox->whereAdd('notice_id > ' . $since_id);
         }
 
-        if ($before_id != 0) {
-            $inbox->whereAdd('notice_id < ' . $before_id);
+        if ($max_id != 0) {
+            $inbox->whereAdd('notice_id <= ' . $max_id);
         }
 
         if (!is_null($since)) {
index d5a280b82cedd18f9ba0df4107b7277c18a4394c..983ea915023ded6aeaae99a9049cfde4ec29b05e 100644 (file)
@@ -2,7 +2,9 @@ INSERT INTO notice_source
     (code, name, url, created)
 VALUES
     ('adium', 'Adium', 'http://www.adiumx.com/', now()),
+    ('Afficheur', 'Afficheur', 'http://afficheur.sourceforge.jp/', now()),
     ('AgentSolo.com','AgentSolo.com','http://www.agentsolo.com/', now()),
+    ('anyio', 'Any.IO', 'http://any.io/', now()),
     ('betwittered','BeTwittered','http://www.32hours.com/betwitteredinfo/', now()),
     ('bti','bti','http://gregkh.github.com/bti/', now()),
     ('cliqset', 'Cliqset', 'http://www.cliqset.com/', now()),
@@ -11,6 +13,7 @@ VALUES
     ('eventbox','EventBox','http://thecosmicmachine.com/eventbox/ ', now()),
     ('Facebook','Facebook','http://apps.facebook.com/identica/', now()),
     ('feed2omb','feed2omb','http://projects.ciarang.com/p/feed2omb/', now()),
+    ('get2gnow', 'get2gnow', 'http://uberchicgeekchick.com/?projects=get2gnow', now()),
     ('gravity', 'Gravity', 'http://mobileways.de/gravity', now()),
     ('Gwibber','Gwibber','http://launchpad.net/gwibber', now()),
     ('HelloTxt','HelloTxt','http://hellotxt.com/', now()),
index 27a1d99dcbbd93e80b43e7d815ee27ba3091fe31..4e1f1dbb1d71ccee1d9407c591ae0c135de637c2 100644 (file)
@@ -335,6 +335,7 @@ function mail_broadcast_notice_sms($notice)
                  "FROM $UT JOIN subscription " .
                  "ON $UT.id = subscription.subscriber " .
                  'WHERE subscription.subscribed = ' . $notice->profile_id . ' ' .
+                 'AND subscription.subscribed != subscription.subscriber ' .
                  "AND $UT.smsemail IS NOT null " .
                  "AND $UT.smsnotify = 1 " .
                  'AND subscription.sms = 1 ');
index e8e1acc4139b6aa59fe916f1938e6817986ffa19..40cb847dfa8434e96f6ca0a388aa7069e867b8f0 100644 (file)
@@ -159,13 +159,9 @@ function omb_post_notice($notice, $remote_profile, $subscription)
 
 function omb_post_notice_keys($notice, $postnoticeurl, $tk, $secret)
 {
-
-    common_debug('Posting notice ' . $notice->id . ' to ' . $postnoticeurl, __FILE__);
-
     $user = User::staticGet('id', $notice->profile_id);
 
     if (!$user) {
-        common_debug('Failed to get user for notice ' . $notice->id . ', profile = ' . $notice->profile_id, __FILE__);
         return false;
     }
 
@@ -208,8 +204,6 @@ function omb_post_notice_keys($notice, $postnoticeurl, $tk, $secret)
                              $req->to_postdata(),
                              array('User-Agent: Laconica/' . LACONICA_VERSION));
 
-    common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__);
-
     if ($result->status == 403) { # not authorized, don't send again
         common_debug('403 result, deleting subscription', __FILE__);
         # FIXME: figure out how to delete this
@@ -286,14 +280,10 @@ function omb_update_profile($profile, $remote_profile, $subscription)
 
     $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
 
-    common_debug('request URL = '.$req->get_normalized_http_url(), __FILE__);
-    common_debug('postdata = '.$req->to_postdata(), __FILE__);
     $result = $fetcher->post($req->get_normalized_http_url(),
                              $req->to_postdata(),
                              array('User-Agent: Laconica/' . LACONICA_VERSION));
 
-    common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__);
-
     if (empty($result) || !$result) {
         common_debug("Unable to contact " . $req->get_normalized_http_url());
     } else if ($result->status == 403) { # not authorized, don't send again
index caf8c071639212a4ec8c7eb19dc37509fddd197e..ca8b03cdcd79f6230df08db5bce0495932cd8773 100644 (file)
@@ -54,7 +54,7 @@ class TwitterapiAction extends Action
     /**
      * Overrides XMLOutputter::element to write booleans as strings (true|false).
      * See that method's documentation for more info.
-     * 
+     *
      * @param string $tag     Element type or tagname
      * @param array  $attrs   Array of element attributes, as
      *                        key-value pairs
@@ -70,24 +70,85 @@ class TwitterapiAction extends Action
 
         return parent::element($tag, $attrs, $content);
     }
-    
+
     function twitter_user_array($profile, $get_notice=false)
     {
-
         $twitter_user = array();
 
+        $twitter_user['id'] = intval($profile->id);
         $twitter_user['name'] = $profile->getBestName();
-        $twitter_user['followers_count'] = $this->count_subscriptions($profile);
         $twitter_user['screen_name'] = $profile->nickname;
-        $twitter_user['description'] = ($profile->bio) ? $profile->bio : null;
         $twitter_user['location'] = ($profile->location) ? $profile->location : null;
-        $twitter_user['id'] = intval($profile->id);
+        $twitter_user['description'] = ($profile->bio) ? $profile->bio : null;
 
         $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
+        $twitter_user['profile_image_url'] = ($avatar) ? $avatar->displayUrl() :
+            Avatar::defaultImage(AVATAR_STREAM_SIZE);
 
-        $twitter_user['profile_image_url'] = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_STREAM_SIZE);
-        $twitter_user['protected'] = false; # not supported by Laconica yet
         $twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null;
+        $twitter_user['protected'] = false; # not supported by Laconica yet
+        $twitter_user['followers_count'] = $this->count_subscriptions($profile);
+
+        // To be supported soon...
+        $twitter_user['profile_background_color'] = '';
+        $twitter_user['profile_text_color'] = '';
+        $twitter_user['profile_link_color'] = '';
+        $twitter_user['profile_sidebar_fill_color'] = '';
+        $twitter_user['profile_sidebar_border_color'] = '';
+
+        $subbed = DB_DataObject::factory('subscription');
+        $subbed->subscriber = $profile->id;
+        $subbed_count = (int) $subbed->count() - 1;
+        $twitter_user['friends_count'] = (is_int($subbed_count)) ? $subbed_count : 0;
+
+        $twitter_user['created_at'] = $this->date_twitter($profile->created);
+
+        $faves = DB_DataObject::factory('fave');
+        $faves->user_id = $user->id;
+        $faves_count = (int) $faves->count();
+        $twitter_user['favourites_count'] = $faves_count; // British spelling!
+
+        // Need to pull up the user for some of this
+        $user = User::staticGet($profile->id);
+
+        $timezone = 'UTC';
+
+        if ($user->timezone) {
+            $timezone = $user->timezone;
+        }
+
+        $t = new DateTime;
+        $t->setTimezone(new DateTimeZone($timezone));
+
+        $twitter_user['utc_offset'] = $t->format('Z');
+        $twitter_user['time_zone'] = $timezone;
+
+        // To be supported some day, perhaps
+        $twitter_user['profile_background_image_url'] = '';
+        $twitter_user['profile_background_tile'] = false;
+
+        $notices = DB_DataObject::factory('notice');
+        $notices->profile_id = $profile->id;
+        $notice_count = (int) $notices->count();
+
+        $twitter_user['statuses_count'] = (is_int($notice_count)) ? $notice_count : 0;
+
+        // Is the requesting user following this user?
+        $twitter_user['following'] = false;
+        $twitter_user['notifications'] = false;
+
+        if (isset($apidata['user'])) {
+
+            $twitter_user['following'] = $apidata['user']->isSubscribed($profile);
+
+            // Notifications on?
+            $sub = Subscription::pkeyGet(array('subscriber' =>
+                $apidata['user']->id, 'subscribed' => $profile->id));
+
+            if ($sub) {
+                $twitter_user['notifications'] = ($sub->jabber || $sub->sms);
+            }
+        }
 
         if ($get_notice) {
             $notice = $profile->getCurrentNotice();
@@ -612,7 +673,27 @@ class TwitterapiAction extends Action
     function get_user($id, $apidata=null)
     {
         if (!$id) {
-            return $apidata['user'];
+            
+            // Twitter supports these other ways of passing the user ID
+            if (is_numeric($this->arg('id'))) {
+                return User::staticGet($this->arg('id'));
+            } else if ($this->arg('id')) {
+                $nickname = common_canonical_nickname($this->arg('id'));
+                return User::staticGet('nickname', $nickname);
+            } else if ($this->arg('user_id')) {
+                // This is to ensure that a non-numeric user_id still 
+                // overrides screen_name even if it doesn't get used
+                if (is_numeric($this->arg('user_id'))) {
+                    return User::staticGet('id', $this->arg('user_id'));
+                }
+            } else if ($this->arg('screen_name')) {
+                $nickname = common_canonical_nickname($this->arg('screen_name'));
+                return User::staticGet('nickname', $nickname);
+            } else {
+                // Fall back to trying the currently authenticated user
+                return $apidata['user'];
+            }
+            
         } else if (is_numeric($id)) {
             return User::staticGet($id);
         } else {
index ab12723098b1b706354257b9f9b4ceba925f15ec..9872d97c4895f8f66cbae97ae4bf565cf817623d 100644 (file)
@@ -900,6 +900,34 @@ function common_enqueue_notice($notice)
     return $result;
 }
 
+function common_post_inbox_transports()
+{
+    $transports = array('omb', 'sms');
+
+    if (common_config('xmpp', 'enabled')) {
+        $transports = array_merge($transports, array('jabber', 'public'));
+    }
+
+    return $transports;
+}
+
+function common_enqueue_notice_transport($notice, $transport)
+{
+    $qi = new Queue_item();
+    $qi->notice_id = $notice->id;
+    $qi->transport = $transport;
+    $qi->created = $notice->created;
+    $result = $qi->insert();
+    if (!$result) {
+        $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError');
+        common_log(LOG_ERR, 'DB error inserting queue item: ' . $last_error->message);
+        throw new ServerException('DB error inserting queue item: ' . $last_error->message);
+>>>>>>> 0.7.x:lib/util.php
+    }
+    common_log(LOG_DEBUG, 'complete queueing notice ID = ' . $notice->id . ' for ' . $transport);
+    return true;
+}
+
 function common_real_broadcast($notice, $remote=false)
 {
     $success = true;
index e5021ff343e5896a0c44f9926cad66792fca572e..1693760914e32e96c6227e4715fd3c669728aead 100644 (file)
@@ -35,107 +35,334 @@ define('LACONICA', true);
 require_once(INSTALLDIR . '/lib/common.php');
 require_once('DB.php');
 
-function fixup_utf8($id) {
+class UTF8FixerUpper
+{
+    var $dbl = null;
+    var $dbu = null;
+    var $args = array();
+
+    function __construct($args)
+    {
+        $this->args = $args;
+
+        if (array_key_exists('max_date', $args)) {
+            $this->max_date = strftime('%Y-%m-%d %H:%M:%S', strtotime($args['max_date']));
+        } else {
+            $this->max_date = strftime('%Y-%m-%d %H:%M:%S', time());
+        }
 
-    $dbl = doConnect('latin1');
+        $this->dbl = $this->doConnect('latin1');
 
-    if (empty($dbl)) {
-        return;
-    }
+        if (empty($this->dbl)) {
+            return;
+        }
 
-    $dbu = doConnect('utf8');
+        $this->dbu = $this->doConnect('utf8');
 
-    if (empty($dbu)) {
-        return;
+        if (empty($this->dbu)) {
+            return;
+        }
     }
 
-    // Do a separate DB connection
+    function doConnect($charset)
+    {
+        $db = DB::connect(common_config('db', 'database'),
+                          array('persistent' => false));
 
-    $sth = $dbu->prepare("UPDATE notice SET content = UNHEX(?), rendered = UNHEX(?) WHERE id = ?");
+        if (PEAR::isError($db)) {
+            echo "ERROR: " . $db->getMessage() . "\n";
+            return NULL;
+        }
 
-    if (PEAR::isError($sth)) {
-        echo "ERROR: " . $sth->getMessage() . "\n";
-        return;
-    }
+        $conn = $db->connection;
 
-    $sql = 'SELECT id, content, rendered FROM notice ' .
-      'WHERE LENGTH(content) != CHAR_LENGTH(content)';
+        $succ = mysqli_set_charset($conn, $charset);
 
-    if (!empty($id)) {
-        $sql .= ' AND id < ' . $id;
-    }
+        if (!$succ) {
+            echo "ERROR: couldn't set charset\n";
+            $db->disconnect();
+            return NULL;
+        }
 
-    $sql .= ' ORDER BY id DESC';
+        $result = $db->autoCommit(true);
 
-    $rn = $dbl->query($sql);
+        if (PEAR::isError($result)) {
+            echo "ERROR: " . $result->getMessage() . "\n";
+            $db->disconnect();
+            return NULL;
+        }
 
-    if (PEAR::isError($rn)) {
-        echo "ERROR: " . $rn->getMessage() . "\n";
-        return;
+        return $db;
     }
 
-    echo "Number of rows: " . $rn->numRows() . "\n";
+    function fixup()
+    {
+        $this->fixupNotices($this->args['max_notice'],
+                            $this->args['min_notice']);
+        $this->fixupProfiles();
+        $this->fixupGroups();
+        $this->fixupMessages();
+    }
 
-    $notice = array();
+    function fixupNotices($max_id, $min_id) {
 
-    while (DB_OK == $rn->fetchInto($notice)) {
+        // Do a separate DB connection
 
-        $id = ($notice[0])+0;
-        $content = bin2hex($notice[1]);
-        $rendered = bin2hex($notice[2]);
+        $sth = $this->dbu->prepare("UPDATE notice SET content = UNHEX(?), rendered = UNHEX(?) WHERE id = ?");
 
-        echo "$id...";
+        if (PEAR::isError($sth)) {
+            echo "ERROR: " . $sth->getMessage() . "\n";
+            return;
+        }
 
-        $result =& $dbu->execute($sth, array($content, $rendered, $id));
+        $sql = 'SELECT id, content, rendered FROM notice ' .
+          'WHERE LENGTH(content) != CHAR_LENGTH(content) '.
+          'AND modified < "'.$this->max_date.'" ';
 
-        if (PEAR::isError($result)) {
-            echo "ERROR: " . $result->getMessage() . "\n";
-            continue;
+        if (!empty($max_id)) {
+            $sql .= ' AND id <= ' . $max_id;
+        }
+
+        if (!empty($min_id)) {
+            $sql .= ' AND id >= ' . $min_id;
         }
 
-        $cnt = $dbu->affectedRows();
+        $sql .= ' ORDER BY id DESC';
 
-        if ($cnt != 1) {
-            echo "ERROR: 0 rows affected\n";
-            continue;
+        $rn = $this->dbl->query($sql);
+
+        if (PEAR::isError($rn)) {
+            echo "ERROR: " . $rn->getMessage() . "\n";
+            return;
         }
 
-        $notice = Notice::staticGet('id', $id);
-        $notice->decache();
+        echo "Number of rows: " . $rn->numRows() . "\n";
 
-        echo "OK\n";
-    }
-}
+        $notice = array();
 
-function doConnect($charset)
-{
-    $db = DB::connect(common_config('db', 'database'),
-                      array('persistent' => false));
+        while (DB_OK == $rn->fetchInto($notice)) {
+
+            $id = ($notice[0])+0;
+            $content = bin2hex($notice[1]);
+            $rendered = bin2hex($notice[2]);
 
-    if (PEAR::isError($db)) {
-        echo "ERROR: " . $db->getMessage() . "\n";
-        return NULL;
+            echo "$id...";
+
+            $result =& $this->dbu->execute($sth, array($content, $rendered, $id));
+
+            if (PEAR::isError($result)) {
+                echo "ERROR: " . $result->getMessage() . "\n";
+                continue;
+            }
+
+            $cnt = $this->dbu->affectedRows();
+
+            if ($cnt != 1) {
+                echo "ERROR: 0 rows affected\n";
+                continue;
+            }
+
+            $notice = Notice::staticGet('id', $id);
+            $notice->decache();
+            $notice->free();
+
+            echo "OK\n";
+        }
     }
 
-    $result = $db->query("SET NAMES $charset");
+    function fixupProfiles()
+    {
+        // Do a separate DB connection
+
+        $sth = $this->dbu->prepare("UPDATE profile SET ".
+                                   "fullname = UNHEX(?),".
+                                   "location = UNHEX(?), ".
+                                   "bio = UNHEX(?) ".
+                                   "WHERE id = ?");
+
+        if (PEAR::isError($sth)) {
+            echo "ERROR: " . $sth->getMessage() . "\n";
+            return;
+        }
+
+        $sql = 'SELECT id, fullname, location, bio FROM profile ' .
+          'WHERE (LENGTH(fullname) != CHAR_LENGTH(fullname) '.
+          'OR LENGTH(location) != CHAR_LENGTH(location) '.
+          'OR LENGTH(bio) != CHAR_LENGTH(bio)) '.
+          'AND modified < "'.$this->max_date.'" '.
+          ' ORDER BY modified DESC';
+
+        $rn = $this->dbl->query($sql);
+
+        if (PEAR::isError($rn)) {
+            echo "ERROR: " . $rn->getMessage() . "\n";
+            return;
+        }
+
+        echo "Number of rows: " . $rn->numRows() . "\n";
+
+        $profile = array();
+
+        while (DB_OK == $rn->fetchInto($profile)) {
+
+            $id = ($profile[0])+0;
+            $fullname = bin2hex($profile[1]);
+            $location = bin2hex($profile[2]);
+            $bio = bin2hex($profile[3]);
+
+            echo "$id...";
+
+            $result =& $this->dbu->execute($sth, array($fullname, $location, $bio, $id));
+
+            if (PEAR::isError($result)) {
+                echo "ERROR: " . $result->getMessage() . "\n";
+                continue;
+            }
+
+            $cnt = $this->dbu->affectedRows();
 
-    if (PEAR::isError($result)) {
-        echo "ERROR: " . $result->getMessage() . "\n";
-        $db->disconnect();
-        return NULL;
+            if ($cnt != 1) {
+                echo "ERROR: 0 rows affected\n";
+                continue;
+            }
+
+            $profile = Profile::staticGet('id', $id);
+            $profile->decache();
+            $profile->free();
+
+            echo "OK\n";
+        }
     }
 
-    $result = $db->autoCommit(true);
+    function fixupGroups()
+    {
+        // Do a separate DB connection
+
+        $sth = $this->dbu->prepare("UPDATE user_group SET ".
+                                   "fullname = UNHEX(?),".
+                                   "location = UNHEX(?), ".
+                                   "description = UNHEX(?) ".
+                                   "WHERE id = ?");
+
+        if (PEAR::isError($sth)) {
+            echo "ERROR: " . $sth->getMessage() . "\n";
+            return;
+        }
+
+        $sql = 'SELECT id, fullname, location, description FROM user_group ' .
+          'WHERE LENGTH(fullname) != CHAR_LENGTH(fullname) '.
+          'OR LENGTH(location) != CHAR_LENGTH(location) '.
+          'OR LENGTH(description) != CHAR_LENGTH(description) ';
+          'AND modified < "'.$this->max_date.'" '.
+          'ORDER BY modified DESC';
+
+        $rn = $this->dbl->query($sql);
+
+        if (PEAR::isError($rn)) {
+            echo "ERROR: " . $rn->getMessage() . "\n";
+            return;
+        }
+
+        echo "Number of rows: " . $rn->numRows() . "\n";
 
-    if (PEAR::isError($result)) {
-        echo "ERROR: " . $result->getMessage() . "\n";
-        $db->disconnect();
-        return NULL;
+        $user_group = array();
+
+        while (DB_OK == $rn->fetchInto($user_group)) {
+
+            $id = ($user_group[0])+0;
+            $fullname = bin2hex($user_group[1]);
+            $location = bin2hex($user_group[2]);
+            $description = bin2hex($user_group[3]);
+
+            echo "$id...";
+
+            $result =& $this->dbu->execute($sth, array($fullname, $location, $description, $id));
+
+            if (PEAR::isError($result)) {
+                echo "ERROR: " . $result->getMessage() . "\n";
+                continue;
+            }
+
+            $cnt = $this->dbu->affectedRows();
+
+            if ($cnt != 1) {
+                echo "ERROR: 0 rows affected\n";
+                continue;
+            }
+
+            $user_group = User_group::staticGet('id', $id);
+            $user_group->decache();
+            $user_group->free();
+
+            echo "OK\n";
+        }
     }
 
-    return $db;
+    function fixupMessages() {
+
+        // Do a separate DB connection
+
+        $sth = $this->dbu->prepare("UPDATE message SET content = UNHEX(?), rendered = UNHEX(?) WHERE id = ?");
+
+        if (PEAR::isError($sth)) {
+            echo "ERROR: " . $sth->getMessage() . "\n";
+            return;
+        }
+
+        $sql = 'SELECT id, content, rendered FROM message ' .
+          'WHERE LENGTH(content) != CHAR_LENGTH(content) '.
+          'AND modified < "'.$this->max_date.'" '.
+          'ORDER BY id DESC';
+
+        $rn = $this->dbl->query($sql);
+
+        if (PEAR::isError($rn)) {
+            echo "ERROR: " . $rn->getMessage() . "\n";
+            return;
+        }
+
+        echo "Number of rows: " . $rn->numRows() . "\n";
+
+        $message = array();
+
+        while (DB_OK == $rn->fetchInto($message)) {
+
+            $id = ($message[0])+0;
+            $content = bin2hex($message[1]);
+            $rendered = bin2hex($message[2]);
+
+            echo "$id...";
+
+            $result =& $this->dbu->execute($sth, array($content, $rendered, $id));
+
+            if (PEAR::isError($result)) {
+                echo "ERROR: " . $result->getMessage() . "\n";
+                continue;
+            }
+
+            $cnt = $this->dbu->affectedRows();
+
+            if ($cnt != 1) {
+                echo "ERROR: 0 rows affected\n";
+                continue;
+            }
+
+            $message = Message::staticGet('id', $id);
+            $message->decache();
+            $message->free();
+
+            echo "OK\n";
+        }
+    }
 }
 
-$id = ($argc > 1) ? $argv[1] : null;
+$max_date = ($argc > 1) ? $argv[1] : null;
+$max_id = ($argc > 2) ? $argv[2] : null;
+$min_id = ($argc > 3) ? $argv[3] : null;
+
+$fixer = new UTF8FixerUpper(array('max_date' => $max_date,
+                                  'max_notice' => $max_id,
+                                  'min_notice' => $min_id));
+
+$fixer->fixup();
 
-fixup_utf8($id);
index a10233e69fcc2ce453a969118eccd867c37c63f7..4e49f9bd4bc776e1ef7b5928dd3deab39972ac89 100755 (executable)
@@ -25,7 +25,6 @@
  * daemon names.
  */
 
-
 # Abort if called from a web server
 if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
     print "This script must be run from the command line\n";
@@ -51,5 +50,4 @@ echo "ombqueuehandler.php ";
 echo "twitterqueuehandler.php ";
 echo "facebookqueuehandler.php ";
 echo "pingqueuehandler.php ";
-echo "inboxqueuehandler.php ";
 echo "smsqueuehandler.php ";
diff --git a/scripts/inboxqueuehandler.php b/scripts/inboxqueuehandler.php
deleted file mode 100755 (executable)
index 73d31e8..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env php
-<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008,2009 Control Yourself, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-// Abort if called from a web server
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('LACONICA', true);
-
-require_once(INSTALLDIR . '/lib/common.php');
-require_once(INSTALLDIR . '/lib/queuehandler.php');
-
-set_error_handler('common_error_handler');
-
-class InboxQueueHandler extends QueueHandler
-{
-    function transport()
-    {
-        return 'inbox';
-    }
-
-       function start() {
-               $this->log(LOG_INFO, "INITIALIZE");
-               return true;
-       }
-
-    function handle_notice($notice)
-    {
-        $this->log(LOG_INFO, "Distributing notice to inboxes for $notice->id");
-        $notice->addToInboxes();
-        $notice->blowSubsCache();
-        return true;
-    }
-
-       function finish() {
-       }
-}
-
-ini_set("max_execution_time", "0");
-ini_set("max_input_time", "0");
-set_time_limit(0);
-mb_internal_encoding('UTF-8');
-
-$id = ($argc > 1) ? $argv[1] : null;
-
-$handler = new InboxQueueHandler($id);
-
-$handler->runOnce();
diff --git a/scripts/memcachedqueuehandler.php b/scripts/memcachedqueuehandler.php
deleted file mode 100755 (executable)
index 185b781..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/env php
-<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008,2009 Control Yourself, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-// Abort if called from a web server
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('LACONICA', true);
-
-require_once(INSTALLDIR . '/lib/common.php');
-require_once(INSTALLDIR . '/lib/queuehandler.php');
-
-set_error_handler('common_error_handler');
-
-class MemcachedQueueHandler extends QueueHandler
-{
-    function transport()
-    {
-        return 'memcache';
-    }
-
-       function start() {
-               $this->log(LOG_INFO, "INITIALIZE");
-               return true;
-       }
-
-    function handle_notice($notice)
-    {
-        // XXX: fork here
-        $this->log(LOG_INFO, "Blowing memcached for $notice->id");
-        $notice->blowCaches();
-        return true;
-    }
-
-       function finish() {
-       }
-
-}
-
-ini_set("max_execution_time", "0");
-ini_set("max_input_time", "0");
-set_time_limit(0);
-mb_internal_encoding('UTF-8');
-
-$id = ($argc > 1) ? $argv[1] : null;
-
-$handler = new MemcachedQueueHandler($id);
-
-$handler->runOnce();
index 764037e8ff0bb4f06d7d6041d0f06437ab22d748..2134b4ab00f2af90e95750a5a24fb9153d97a917 100755 (executable)
@@ -24,8 +24,7 @@ SDIR=`dirname $0`
 DIR=`php $SDIR/getpiddir.php`
 
 for f in jabberhandler ombhandler publichandler smshandler pinghandler \
-        xmppconfirmhandler xmppdaemon twitterhandler facebookhandler \
-         memcachehandler inboxhandler twitterstatusfetcher; do
+        xmppconfirmhandler xmppdaemon twitterhandler facebookhandler; do
 
        FILES="$DIR/$f.*.pid"
        for ff in "$FILES" ; do