]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge commit 'refs/merge-requests/19' of https://gitorious.org/social/mainline into...
authorMikael Nordfeldth <mmn@hethane.se>
Sat, 6 Dec 2014 19:18:52 +0000 (20:18 +0100)
committerMikael Nordfeldth <mmn@hethane.se>
Sat, 6 Dec 2014 19:18:52 +0000 (20:18 +0100)
104 files changed:
EVENTS.txt
INSTALL
README.md
UPGRADE
actions/apidirectmessage.php [deleted file]
actions/apidirectmessagenew.php [deleted file]
actions/apisearchatom.php
actions/apistatusesupdate.php
actions/apitimelineuser.php
actions/deletegroup.php
actions/inbox.php [deleted file]
actions/newmessage.php [deleted file]
actions/outbox.php [deleted file]
actions/showmessage.php [deleted file]
classes/Conversation.php
classes/Message.php [deleted file]
classes/Notice.php
classes/Profile.php
db/core.php
lib/accountprofileblock.php
lib/activity.php
lib/activitycontext.php
lib/activityhandlerplugin.php
lib/apiaction.php
lib/apiauthaction.php
lib/command.php
lib/commandinterpreter.php
lib/default.php
lib/framework.php
lib/jsonsearchresultslist.php
lib/mail.php
lib/mailbox.php [deleted file]
lib/mailboxmenu.php [deleted file]
lib/messageform.php [deleted file]
lib/messagelist.php [deleted file]
lib/messagelistitem.php [deleted file]
lib/microappplugin.php
lib/noticelistitem.php
lib/personalgroupnav.php
lib/router.php
lib/searchaction.php
lib/threadednoticelist.php
lib/useractivitystream.php
lib/util.php
lib/xmloutputter.php
plugins/AccountManager/AccountManagerPlugin.php
plugins/ActivitySpam/ActivitySpamPlugin.php
plugins/BitlyUrl/BitlyUrlPlugin.php
plugins/Blacklist/BlacklistPlugin.php
plugins/Blog/BlogPlugin.php
plugins/Bookmark/BookmarkPlugin.php
plugins/Bookmark/lib/bookmarklistitem.php [deleted file]
plugins/ConversationTree/lib/conversationtreeitem.php
plugins/DirectMessage/DirectMessagePlugin.php [new file with mode: 0644]
plugins/DirectMessage/actions/apidirectmessage.php [new file with mode: 0644]
plugins/DirectMessage/actions/apidirectmessagenew.php [new file with mode: 0644]
plugins/DirectMessage/actions/inbox.php [new file with mode: 0644]
plugins/DirectMessage/actions/newmessage.php [new file with mode: 0644]
plugins/DirectMessage/actions/outbox.php [new file with mode: 0644]
plugins/DirectMessage/actions/showmessage.php [new file with mode: 0644]
plugins/DirectMessage/classes/Message.php [new file with mode: 0644]
plugins/DirectMessage/lib/inboxmessagelist.php [new file with mode: 0644]
plugins/DirectMessage/lib/mailboxaction.php [new file with mode: 0644]
plugins/DirectMessage/lib/mailboxmenu.php [new file with mode: 0644]
plugins/DirectMessage/lib/messagecommand.php [new file with mode: 0644]
plugins/DirectMessage/lib/messageform.php [new file with mode: 0644]
plugins/DirectMessage/lib/messagelist.php [new file with mode: 0644]
plugins/DirectMessage/lib/messagelistitem.php [new file with mode: 0644]
plugins/Directory/DirectoryPlugin.php
plugins/Directory/lib/sortablegrouplist.php
plugins/Event/EventPlugin.php
plugins/Event/classes/RSVP.php
plugins/Event/lib/eventlistitem.php [deleted file]
plugins/Event/lib/rsvplistitem.php [deleted file]
plugins/ExtendedProfile/ExtendedProfilePlugin.php
plugins/FacebookBridge/FacebookBridgePlugin.php
plugins/Favorite/FavoritePlugin.php
plugins/GNUsocialProfileExtensions/lib/noticetree.php
plugins/GroupFavorited/GroupFavoritedPlugin.php
plugins/GroupPrivateMessage/GroupPrivateMessagePlugin.php
plugins/LinkPreview/LinkPreviewPlugin.php
plugins/ModPlus/ModPlusPlugin.php
plugins/OStatus/OStatusPlugin.php
plugins/OStatus/classes/Magicsig.php
plugins/OStatus/classes/Ostatus_profile.php
plugins/OpenID/OpenIDPlugin.php
plugins/Poll/PollPlugin.php
plugins/Poll/lib/polllistitem.php [deleted file]
plugins/QnA/QnAPlugin.php
plugins/Realtime/RealtimePlugin.php
plugins/Sample/SamplePlugin.php
plugins/SearchSub/SearchSubPlugin.php
plugins/Sitemap/SitemapPlugin.php
plugins/SlicedFavorites/SlicedFavoritesPlugin.php
plugins/SubMirror/SubMirrorPlugin.php
plugins/TagSub/TagSubPlugin.php
plugins/TwitterBridge/README
plugins/TwitterBridge/TwitterBridgePlugin.php
plugins/UserFlag/UserFlagPlugin.php
plugins/YammerImport/YammerImportPlugin.php
scripts/createsim.php
scripts/upgrade.php
theme/base/css/display.css
theme/neo/css/display.css

index 255869afda41845dd1cd1654358d443f37aaf599..e70dae69309a7dba0dd26b3fe29bc30af25d434e 100644 (file)
@@ -257,6 +257,22 @@ StartShowNoticeItem: just before showing the notice item
 EndShowNoticeItem: just after showing the notice item
 - $item: the NoticeListItem object being shown
 
+StartShowNoticeItemNotice: just before outputting the "top" notice part of a NoticeListItem to HTML
+- $item: The NoticeListItem object being shown
+
+EndShowNoticeItemNotice: just after outputting the "top" notice part of a NoticeListItem to HTML
+- $item: The NoticeListItem object being shown
+
+StartShowNoticeContent: just before outputting the content part of a Notice
+- $stored: The Notice object
+- $out: HTMLOutputter for writing to
+- $scoped: optional Profile object for permission scoping
+
+EndShowNoticeContent: just after outputting the content part of a Notice, plugins must call this manually
+- $stored: The Notice object
+- $out: HTMLOutputter for writing to
+- $scoped: optional Profile object for permission scoping
+
 StartShowNoticeInfo: just before showing notice info
 - $item: The NoticeListItem object being shown
 
diff --git a/INSTALL b/INSTALL
index 57888e008fbf94d7b60f81f545b9a5cea672812e..d1d5722e7b6fde649a5663ca8ba4e2993a35ae2b 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -7,7 +7,7 @@ run correctly.
 - PHP 5.4+      For newer versions, some functions that are used may be
                 disabled by default, such as the pcntl_* family. See the
                 section on 'Queues and daemons' for more information.
-- MariaDB 5.x   GNU Social uses, by default, a MariaDB server for data
+- MariaDB 5   GNU Social uses, by default, a MariaDB server for data
                 storage. Versions 5.x and 10.x have both reportedly
                 worked well. It is also possible to run MySQL 5.x.
 - Web server    Apache, lighttpd and nginx will all work. CGI mode is
@@ -18,13 +18,17 @@ run correctly.
 Your PHP installation must include the following PHP extensions for a
 functional setup of GNU Social:
 
-- Curl          Fetching files by HTTP.
-- XMLWriter     For formatting XML and HTML output.
-- mysqlnd       The native driver for PHP5 MariaDB connections. If you
-                use MySQL, 'mysql' or 'mysqli' may work.
-- GD            Image manipulation (scaling).
-- mbstring      For handling Unicode (UTF-8) encoded strings.
-- bcmath or gmp For Salmon signatures (part of OStatus).
+- openssl       (compiled in for Debian, enabled manually in Arch Linux)
+- php5-curl     Fetching files by HTTP.
+- php5-gd       Image manipulation (scaling).
+- php5-gmp      For Salmon signatures (part of OStatus).
+- php5-json     For WebFinger lookups and more.
+- php5-mysqlnd  The native driver for PHP5 MariaDB connections. If you
+                  use MySQL, 'mysql' or 'mysqli' may work.
+
+The above package names are for Debian based systems. In the case of
+Arch Linux, PHP is compiled with support for most extensions but they
+require manual enabling in the relevant php.ini file (mostly php5-gmp).
 
 Better performance
 ------------------
index c705dd54125d6b3985a1ae422f1c0f5176921e00..0bf73ae44cc051f6156dd38ec7e5829595852cbd 100644 (file)
--- a/README.md
+++ b/README.md
@@ -118,7 +118,7 @@ Upgrades from _StatusNet_ 1.1.1 will also experience these improvements:
 - More robust handling of errors in distribution.
 - Fix error in OStatus subscription for remote groups.
 - Fix error in XMPP distribution.
-
+- Tracking of conversation URI metadata (more coherent convos)
 
 ### Troubleshooting
 
diff --git a/UPGRADE b/UPGRADE
index db16cf2a60caaaf31d23a6e660ced8c6d993cef4..10758c52e4c6d3c1535c7e4498b9055ab13f2ce7 100644 (file)
--- a/UPGRADE
+++ b/UPGRADE
@@ -9,6 +9,8 @@ We cannot support migrating from any other version of StatusNet than
 follow the upgrade procedures for each respective StatusNet version.
 
 You are now running StatusNet 1.1.1 and want to migrate to GNU social.
+Beware there may be changes in minimum required version of PHP and the
+modules used, so double-check the INSTALL file's requirements list.
 
 Before you begin: Make backups. Always make backups. Of your entire 
 directory structure and the database too. All tables. All data. Alles.
@@ -35,7 +37,7 @@ directory structure and the database too. All tables. All data. Alles.
     
     5. Start your queue daemons: 'php scripts/startdaemons.php'
     
-    6. Report any issues at https://gitorious.org/statusnet/gnu-social/ 
+    6. Report any issues at https://bugz.foocorp.net/ (tag GNU social)
 
 
 Legacy StatusNet instructions
@@ -95,22 +97,3 @@ panels from /admin/* to /panel/*. This now allows the (popular)
 username 'admin', but blocks the considerably less popular username
 'panel'. If you have an existing user named 'panel', you should rename
 them before upgrading.
-
-Privacy
-=======
-
-With StatusNet 1.0, our default install profile is for private sites.
-
-If you did not specify the privacy level of your site previously, it
-was public. Now, it's private.
-
-If you upgrade a public site, you will need to reset the privacy
-level. You can do this in your config.php:
-
-       $config['site']['private'] = false;
-
-...or with setconfig.php in the db:
-
-       php setconfig.php site private false
-
-...or with the site admin panel.
diff --git a/actions/apidirectmessage.php b/actions/apidirectmessage.php
deleted file mode 100644 (file)
index e971a7d..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Show a the direct messages from or to a user
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  API
- * @package   StatusNet
- * @author    Adrian Lang <mail@adrianlang.de>
- * @author    Evan Prodromou <evan@status.net>
- * @author    Robin Millette <robin@millette.info>
- * @author    Zach Copley <zach@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-/**
- * Show a list of direct messages from or to the authenticating user
- *
- * @category API
- * @package  StatusNet
- * @author   Adrian Lang <mail@adrianlang.de>
- * @author   Evan Prodromou <evan@status.net>
- * @author   Robin Millette <robin@millette.info>
- * @author   Zach Copley <zach@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- */
-class ApiDirectMessageAction extends ApiAuthAction
-{
-    var $messages     = null;
-    var $title        = null;
-    var $subtitle     = null;
-    var $link         = null;
-    var $selfuri_base = null;
-    var $id           = null;
-
-    /**
-     * Take arguments for running
-     *
-     * @param array $args $_REQUEST args
-     *
-     * @return boolean success flag
-     */
-    function prepare($args)
-    {
-        parent::prepare($args);
-
-        $this->user = $this->auth_user;
-
-        if (empty($this->user)) {
-            // TRANS: Client error given when a user was not found (404).
-            $this->clientError(_('No such user.'), 404);
-        }
-
-        $server   = common_root_url();
-        $taguribase = TagURI::base();
-
-        if ($this->arg('sent')) {
-
-            // Action was called by /api/direct_messages/sent.format
-
-            $this->title = sprintf(
-                // TRANS: Title. %s is a user nickname.
-                _("Direct messages from %s"),
-                $this->user->nickname
-            );
-            $this->subtitle = sprintf(
-                // TRANS: Subtitle. %s is a user nickname.
-                _("All the direct messages sent from %s"),
-                $this->user->nickname
-            );
-            $this->link = $server . $this->user->nickname . '/outbox';
-            $this->selfuri_base = common_root_url() . 'api/direct_messages/sent';
-            $this->id = "tag:$taguribase:SentDirectMessages:" . $this->user->id;
-        } else {
-            $this->title = sprintf(
-                // TRANS: Title. %s is a user nickname.
-                _("Direct messages to %s"),
-                $this->user->nickname
-            );
-            $this->subtitle = sprintf(
-                // TRANS: Subtitle. %s is a user nickname.
-                _("All the direct messages sent to %s"),
-                $this->user->nickname
-            );
-            $this->link = $server . $this->user->nickname . '/inbox';
-            $this->selfuri_base = common_root_url() . 'api/direct_messages';
-            $this->id = "tag:$taguribase:DirectMessages:" . $this->user->id;
-        }
-
-        $this->messages = $this->getMessages();
-
-        return true;
-    }
-
-    /**
-     * Handle the request
-     *
-     * Show the messages
-     *
-     * @param array $args $_REQUEST data (unused)
-     *
-     * @return void
-     */
-    function handle($args)
-    {
-        parent::handle($args);
-        $this->showMessages();
-    }
-
-    /**
-     * Show the messages
-     *
-     * @return void
-     */
-    function showMessages()
-    {
-        switch($this->format) {
-        case 'xml':
-            $this->showXmlDirectMessages();
-            break;
-        case 'rss':
-            $this->showRssDirectMessages();
-            break;
-        case 'atom':
-            $this->showAtomDirectMessages();
-            break;
-        case 'json':
-            $this->showJsonDirectMessages();
-            break;
-        default:
-            // TRANS: Client error displayed when coming across a non-supported API method.
-            $this->clientError(_('API method not found.'), $code = 404);
-            break;
-        }
-    }
-
-    /**
-     * Get notices
-     *
-     * @return array notices
-     */
-    function getMessages()
-    {
-        $message  = new Message();
-
-        if ($this->arg('sent')) {
-            $message->from_profile = $this->user->id;
-        } else {
-            $message->to_profile = $this->user->id;
-        }
-
-        if (!empty($this->max_id)) {
-            $message->whereAdd('id <= ' . $this->max_id);
-        }
-
-        if (!empty($this->since_id)) {
-            $message->whereAdd('id > ' . $this->since_id);
-        }
-
-        $message->orderBy('created DESC, id DESC');
-        $message->limit((($this->page - 1) * $this->count), $this->count);
-        $message->find();
-
-        $messages = array();
-
-        while ($message->fetch()) {
-            $messages[] = clone($message);
-        }
-
-        return $messages;
-    }
-
-    /**
-     * Is this action read only?
-     *
-     * @param array $args other arguments
-     *
-     * @return boolean true
-     */
-    function isReadOnly($args)
-    {
-        return true;
-    }
-
-    /**
-     * When was this notice last modified?
-     *
-     * @return string datestamp of the latest notice in the stream
-     */
-    function lastModified()
-    {
-        if (!empty($this->messages)) {
-            return strtotime($this->messages[0]->created);
-        }
-
-        return null;
-    }
-
-    /**
-     * Shows a list of direct messages as Twitter-style XML array
-     *
-     * @return void
-     */
-    function showXmlDirectMessages()
-    {
-        $this->initDocument('xml');
-        $this->elementStart('direct-messages', array('type' => 'array',
-                                                     'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
-
-        foreach ($this->messages as $m) {
-            $dm_array = $this->directMessageArray($m);
-            $this->showXmlDirectMessage($dm_array);
-        }
-
-        $this->elementEnd('direct-messages');
-        $this->endDocument('xml');
-    }
-
-    /**
-     * Shows a list of direct messages as a JSON encoded array
-     *
-     * @return void
-     */
-    function showJsonDirectMessages()
-    {
-        $this->initDocument('json');
-
-        $dmsgs = array();
-
-        foreach ($this->messages as $m) {
-            $dm_array = $this->directMessageArray($m);
-            array_push($dmsgs, $dm_array);
-        }
-
-        $this->showJsonObjects($dmsgs);
-        $this->endDocument('json');
-    }
-
-    /**
-     * Shows a list of direct messages as RSS items
-     *
-     * @return void
-     */
-    function showRssDirectMessages()
-    {
-        $this->initDocument('rss');
-
-        $this->element('title', null, $this->title);
-
-        $this->element('link', null, $this->link);
-        $this->element('description', null, $this->subtitle);
-        $this->element('language', null, 'en-us');
-
-        $this->element(
-            'atom:link',
-            array(
-                'type' => 'application/rss+xml',
-                'href' => $this->selfuri_base . '.rss',
-                'rel' => self
-                ),
-            null
-        );
-        $this->element('ttl', null, '40');
-
-        foreach ($this->messages as $m) {
-            $entry = $this->rssDirectMessageArray($m);
-            $this->showTwitterRssItem($entry);
-        }
-
-        $this->endTwitterRss();
-    }
-
-    /**
-     * Shows a list of direct messages as Atom entries
-     *
-     * @return void
-     */
-    function showAtomDirectMessages()
-    {
-        $this->initDocument('atom');
-
-        $this->element('title', null, $this->title);
-        $this->element('id', null, $this->id);
-
-        $selfuri = common_root_url() . 'api/direct_messages.atom';
-
-        $this->element(
-            'link', array(
-            'href' => $this->link,
-            'rel' => 'alternate',
-            'type' => 'text/html'),
-            null
-        );
-        $this->element(
-            'link', array(
-            'href' => $this->selfuri_base . '.atom', 'rel' => 'self',
-            'type' => 'application/atom+xml'),
-            null
-        );
-        $this->element('updated', null, common_date_iso8601('now'));
-        $this->element('subtitle', null, $this->subtitle);
-
-        foreach ($this->messages as $m) {
-            $entry = $this->rssDirectMessageArray($m);
-            $this->showTwitterAtomEntry($entry);
-        }
-
-        $this->endDocument('atom');
-    }
-
-    /**
-     * An entity tag for this notice
-     *
-     * Returns an Etag based on the action name, language, and
-     * timestamps of the notice
-     *
-     * @return string etag
-     */
-    function etag()
-    {
-        if (!empty($this->messages)) {
-
-            $last = count($this->messages) - 1;
-
-            return '"' . implode(
-                ':',
-                array($this->arg('action'),
-                      common_user_cache_hash($this->auth_user),
-                      common_language(),
-                      strtotime($this->messages[0]->created),
-                      strtotime($this->messages[$last]->created)
-                )
-            )
-            . '"';
-        }
-
-        return null;
-    }
-}
diff --git a/actions/apidirectmessagenew.php b/actions/apidirectmessagenew.php
deleted file mode 100644 (file)
index 653fa3a..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Send a direct message via the API
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  API
- * @package   StatusNet
- * @author    Adrian Lang <mail@adrianlang.de>
- * @author    Evan Prodromou <evan@status.net>
- * @author    Robin Millette <robin@millette.info>
- * @author    Zach Copley <zach@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-/**
- * Creates a new direct message from the authenticating user to
- * the user specified by id.
- *
- * @category API
- * @package  StatusNet
- * @author   Adrian Lang <mail@adrianlang.de>
- * @author   Evan Prodromou <evan@status.net>
- * @author   Robin Millette <robin@millette.info>
- * @author   Zach Copley <zach@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- */
-class ApiDirectMessageNewAction extends ApiAuthAction
-{
-    protected $needPost = true;
-
-    var $other   = null;    // Profile we're sending to
-    var $content = null;
-
-    /**
-     * Take arguments for running
-     *
-     * @param array $args $_REQUEST args
-     *
-     * @return boolean success flag
-     */
-    protected function prepare(array $args=array())
-    {
-        parent::prepare($args);
-
-        if (empty($this->user)) {
-            // TRANS: Client error when user not found for an API direct message action.
-            $this->clientError(_('No such user.'), 404);
-        }
-
-        $this->content = $this->trimmed('text');
-
-        $user_param  = $this->trimmed('user');
-        $user_id     = $this->arg('user_id');
-        $screen_name = $this->trimmed('screen_name');
-
-        if (isset($user_param) || isset($user_id) || isset($screen_name)) {
-            $this->other = $this->getTargetProfile($user_param);
-        }
-
-        return true;
-    }
-
-    /**
-     * Handle the request
-     *
-     * Save the new message
-     *
-     * @return void
-     */
-    protected function handle()
-    {
-        parent::handle();
-
-        if (empty($this->content)) {
-            // TRANS: Client error displayed when no message text was submitted (406).
-            $this->clientError(_('No message text!'), 406);
-        } else {
-            $content_shortened = $this->auth_user->shortenLinks($this->content);
-            if (Message::contentTooLong($content_shortened)) {
-                // TRANS: Client error displayed when message content is too long.
-                // TRANS: %d is the maximum number of characters for a message.
-                $this->clientError(
-                    sprintf(_m('That\'s too long. Maximum message size is %d character.', 'That\'s too long. Maximum message size is %d characters.', Message::maxContent()), Message::maxContent()),
-                    406);
-            }
-        }
-
-        if (!$this->other instanceof Profile) {
-            // TRANS: Client error displayed if a recipient user could not be found (403).
-            $this->clientError(_('Recipient user not found.'), 403);
-        } else if (!$this->user->mutuallySubscribed($this->other)) {
-            // TRANS: Client error displayed trying to direct message another user who's not a friend (403).
-            $this->clientError(_('Cannot send direct messages to users who aren\'t your friend.'), 403);
-        } else if ($this->user->id == $this->other->id) {
-
-            // Note: sending msgs to yourself is allowed by Twitter
-
-            // TRANS: Client error displayed trying to direct message self (403).
-            $this->clientError(_('Do not send a message to yourself; just say it to yourself quietly instead.'), 403);
-        }
-
-        $message = Message::saveNew(
-            $this->user->id,
-            $this->other->id,
-            html_entity_decode($this->content, ENT_NOQUOTES, 'UTF-8'),
-            $this->source
-        );
-
-        $message->notify();
-
-        if ($this->format == 'xml') {
-            $this->showSingleXmlDirectMessage($message);
-        } elseif ($this->format == 'json') {
-            $this->showSingleJsondirectMessage($message);
-        }
-    }
-}
index fdf95f1ce9fdcd8bc5290ba8d078ca8d82f25f52..b686edb00aeabb9a89e0243e23f1bf93ec6a59ae 100644 (file)
@@ -339,7 +339,7 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
         $source = null;
 
         $ns = $notice->getSource();
-        if ($ns) {
+        if ($ns instanceof Notice_source) {
             if (!empty($ns->name) && !empty($ns->url)) {
                 $source = '<a href="'
                    . htmlspecialchars($ns->url)
index 7bc5d899ef96a57e5f0348c9758531509c97fd21..b9c229ed4ecddf5ca8fd767d4c2a73ddf0250de5 100644 (file)
@@ -336,7 +336,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
      */
     function supported($cmd)
     {
-        static $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand',
+        static $cmdlist = array('SubCommand', 'UnsubCommand',
             'OnCommand', 'OffCommand', 'JoinCommand', 'LeaveCommand');
 
         $supported = null;
index 97462452f22c0642453df81aedb56df3e2213fea..26c960fa0429b9e1d176713cd4e65e60be43ddfa 100644 (file)
@@ -134,12 +134,17 @@ class ApiTimelineUserAction extends ApiBareAuthAction
                                           'id' => $this->target->id),
                                     array('max_id' => $this->next_id))
                     : null;
-        $lastNotice = $this->notices[0];
-        $lastId     = $lastNotice->id;
+
+        $prevExtra = array();
+        if (!empty($this->notices)) {
+            assert($this->notices[0] instanceof Notice);
+            $prevExtra['since_id'] = $this->notices[0]->id;
+        }
+
         $prevUrl = common_local_url('ApiTimelineUser',
                                     array('format' => $this->format,
                                           'id' => $this->target->id),
-                                    array('since_id' => $lastId));
+                                    $prevExtra);
         $firstUrl = common_local_url('ApiTimelineUser',
                                     array('format' => $this->format,
                                           'id' => $this->target->id));
@@ -224,7 +229,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
             break;
         default:
             // TRANS: Client error displayed when coming across a non-supported API method.
-            $this->clientError(_('API method not found.'), $code = 404);
+            $this->clientError(_('API method not found.'), 404);
         }
     }
 
index 6d9d66d30e1f61ec86c8397373a63106b24414ab..c64bc1d8e90fd47fb91cfd4d0cd4743b358f8ad0 100644 (file)
@@ -171,6 +171,8 @@ class DeletegroupAction extends RedirectingAction
 
     function showContent() {
         $this->areYouSureForm();
+        $block = new GroupProfileBlock($this, $this->group);
+        $block->show();
     }
 
     /**
diff --git a/actions/inbox.php b/actions/inbox.php
deleted file mode 100644 (file)
index e9aa343..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * action handler for message inbox
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Message
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2008 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
-    exit(1);
-}
-
-require_once INSTALLDIR.'/lib/mailbox.php';
-
-/**
- * action handler for message inbox
- *
- * @category Message
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- * @see      MailboxAction
- */
-class InboxAction extends MailboxAction
-{
-
-    /**
-     * Title of the page
-     *
-     * @return string page title
-     */
-    function title()
-    {
-        if ($this->page > 1) {
-            // TRANS: Title for all but the first page of the inbox page.
-            // TRANS: %1$s is the user's nickname, %2$s is the page number.
-            return sprintf(_('Inbox for %1$s - page %2$d'), $this->user->nickname,
-                $this->page);
-        } else {
-            // TRANS: Title for the first page of the inbox page.
-            // TRANS: %s is the user's nickname.
-            return sprintf(_('Inbox for %s'), $this->user->nickname);
-        }
-    }
-
-    /**
-     * Retrieve the messages for this user and this page
-     *
-     * Does a query for the right messages
-     *
-     * @return Message data object with stream for messages
-     *
-     * @see MailboxAction::getMessages()
-     */
-    function getMessages()
-    {
-        $message = new Message();
-
-        $message->to_profile = $this->user->id;
-        $message->orderBy('created DESC, id DESC');
-        $message->limit((($this->page - 1) * MESSAGES_PER_PAGE),
-            MESSAGES_PER_PAGE + 1);
-
-        if ($message->find()) {
-            return $message;
-        } else {
-            return null;
-        }
-    }
-
-    function getMessageList($message)
-    {
-        return new InboxMessageList($this, $message);
-    }
-
-    /**
-     * Instructions for using this page
-     *
-     * @return string localised instructions for using the page
-     */
-    function getInstructions()
-    {
-        // TRANS: Instructions for user inbox page.
-        return _('This is your inbox, which lists your incoming private messages.');
-    }
-}
-
-class InboxMessageList extends MessageList
-{
-    function newItem($message)
-    {
-        return new InboxMessageListItem($this->out, $message);
-    }
-}
-
-class InboxMessageListItem extends MessageListItem
-{
-    /**
-     * Returns the profile we want to show with the message
-     *
-     * @return Profile The profile that matches the message
-     */
-    function getMessageProfile()
-    {
-        return $this->message->getFrom();
-    }
-}
diff --git a/actions/newmessage.php b/actions/newmessage.php
deleted file mode 100644 (file)
index 428a557..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Handler for posting new messages
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Personal
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @author    Zach Copley <zach@status.net>
- * @author    Sarven Capadisli <csarven@status.net>
- * @copyright 2008-2009 StatusNet, Inc.
- * @copyright 2013 Free Software Foundation, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    exit(1);
-}
-
-/**
- * Action for posting new direct messages
- *
- * @category Personal
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @author   Zach Copley <zach@status.net>
- * @author   Sarven Capadisli <csarven@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- */
-
-class NewmessageAction extends FormAction
-{
-    var $content = null;
-    var $to = null;
-    var $other = null;
-
-    /**
-     * Title of the page
-     *
-     * Note that this usually doesn't get called unless something went wrong
-     *
-     * @return string page title
-     */
-
-    function title()
-    {
-        // TRANS: Page title for new direct message page.
-        return _('New message');
-    }
-
-    /**
-     * Handle input, produce output
-     *
-     * @param array $args $_REQUEST contents
-     *
-     * @return void
-     */
-
-    protected function prepare(array $args=array())
-    {
-        parent::prepare($args);
-
-        $this->content = $this->trimmed('content');
-        $this->to = $this->trimmed('to');
-
-        if ($this->to) {
-
-            $this->other = Profile::getKV('id', $this->to);
-
-            if (!$this->other instanceof Profile) {
-                // TRANS: Client error displayed trying to send a direct message to a non-existing user.
-                $this->clientError(_('No such user.'), 404);
-            }
-
-            if (!$this->other->isLocal()) {
-                // TRANS: Explains that current federation does not support direct, private messages yet.
-                $this->clientError(_('You cannot send direct messages to federated users yet.'));
-            }
-
-            if (!$this->scoped->mutuallySubscribed($this->other)) {
-                // TRANS: Client error displayed trying to send a direct message to a user while sender and
-                // TRANS: receiver are not subscribed to each other.
-                $this->clientError(_('You cannot send a message to this user.'), 404);
-            }
-        }
-
-        return true;
-    }
-
-    protected function handlePost()
-    {
-        parent::handlePost();
-
-        assert($this->scoped instanceof Profile); // XXX: maybe an error instead...
-
-        if (!$this->content) {
-            // TRANS: Form validator error displayed trying to send a direct message without content.
-            $this->clientError(_('No content!'));
-        } else {
-            $content_shortened = $this->scoped->shortenLinks($this->content);
-
-            if (Message::contentTooLong($content_shortened)) {
-                // TRANS: Form validation error displayed when message content is too long.
-                // TRANS: %d is the maximum number of characters for a message.
-                $this->clientError(sprintf(_m('That\'s too long. Maximum message size is %d character.',
-                                           'That\'s too long. Maximum message size is %d characters.',
-                                           Message::maxContent()),
-                                        Message::maxContent()));
-            }
-        }
-
-        if (!$this->other) {
-            // TRANS: Form validation error displayed trying to send a direct message without specifying a recipient.
-            $this->clientError(_('No recipient specified.'));
-        } else if (!$this->scoped->mutuallySubscribed($this->other)) {
-            // TRANS: Client error displayed trying to send a direct message to a user while sender and
-            // TRANS: receiver are not subscribed to each other.
-            $this->clientError(_('You cannot send a message to this user.'), 404);
-        } else if ($this->scoped->id == $this->other->id) {
-            // TRANS: Client error displayed trying to send a direct message to self.
-            $this->clientError(_('Do not send a message to yourself; ' .
-                'just say it to yourself quietly instead.'), 403);
-        }
-
-        $message = Message::saveNew($this->scoped->id, $this->other->id, $this->content, 'web');
-        $message->notify();
-
-        if ($this->boolean('ajax')) {
-            $this->startHTML('text/xml;charset=utf-8');
-            $this->elementStart('head');
-            // TRANS: Page title after sending a direct message.
-            $this->element('title', null, _('Message sent'));
-            $this->elementEnd('head');
-            $this->elementStart('body');
-            $this->element('p', array('id' => 'command_result'),
-                // TRANS: Confirmation text after sending a direct message.
-                // TRANS: %s is the direct message recipient.
-                sprintf(_('Direct message to %s sent.'),
-                    $this->other->nickname));
-            $this->elementEnd('body');
-            $this->endHTML();
-        } else {
-            $url = common_local_url('outbox',
-                array('nickname' => $this->scoped->nickname));
-            common_redirect($url, 303);
-        }
-    }
-
-    /**
-     * Show an Ajax-y error message
-     *
-     * Goes back to the browser, where it's shown in a popup.
-     *
-     * @param string $msg Message to show
-     *
-     * @return void
-     */
-
-    function ajaxErrorMsg($msg)
-    {
-        $this->startHTML('text/xml;charset=utf-8', true);
-        $this->elementStart('head');
-        // TRANS: Page title after an AJAX error occurred on the "send direct message" page.
-        $this->element('title', null, _('Ajax Error'));
-        $this->elementEnd('head');
-        $this->elementStart('body');
-        $this->element('p', array('id' => 'error'), $msg);
-        $this->elementEnd('body');
-        $this->endHTML();
-    }
-
-    function showForm($msg = null)
-    {
-        if ($msg && $this->boolean('ajax')) {
-            $this->ajaxErrorMsg($msg);
-            return;
-        }
-
-        $this->msg = $msg;
-        if ($this->trimmed('ajax')) {
-            $this->startHTML('text/xml;charset=utf-8');
-            $this->elementStart('head');
-            // TRANS: Page title on page for sending a direct message.
-            $this->element('title', null, _('New message'));
-            $this->elementEnd('head');
-            $this->elementStart('body');
-            $this->showNoticeForm();
-            $this->elementEnd('body');
-            $this->endHTML();
-        }
-        else {
-            $this->showPage();
-        }
-    }
-
-    function showPageNotice()
-    {
-        if ($this->msg) {
-            $this->element('p', 'error', $this->msg);
-        }
-    }
-
-    // Do nothing (override)
-
-    function showNoticeForm()
-    {
-        $message_form = new MessageForm($this, $this->other, $this->content);
-        $message_form->show();
-    }
-}
diff --git a/actions/outbox.php b/actions/outbox.php
deleted file mode 100644 (file)
index 6d10c81..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * action handler for message inbox
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Message
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2008 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-if (!defined('STATUSNET') && !defined('LACONICA')) {
-    exit(1);
-}
-
-require_once INSTALLDIR.'/lib/mailbox.php';
-
-/**
- * action handler for message outbox
- *
- * @category Message
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- * @see      MailboxAction
- */
-class OutboxAction extends MailboxAction
-{
-    /**
-     * Title of the page
-     *
-     * @return string page title
-     */
-    function title()
-    {
-        if ($this->page > 1) {
-            // TRANS: Title for outbox for any but the fist page.
-            // TRANS: %1$s is the user nickname, %2$d is the page number.
-            return sprintf(_('Outbox for %1$s - page %2$d'),
-                $this->user->nickname, $page);
-        } else {
-            // TRANS: Title for first page of outbox.
-            return sprintf(_('Outbox for %s'), $this->user->nickname);
-        }
-    }
-
-    /**
-     * retrieve the messages for this user and this page
-     *
-     * Does a query for the right messages
-     *
-     * @return Message data object with stream for messages
-     *
-     * @see MailboxAction::getMessages()
-     */
-    function getMessages()
-    {
-        $message = new Message();
-
-        $message->from_profile = $this->user->id;
-        $message->orderBy('created DESC, id DESC');
-        $message->limit((($this->page - 1) * MESSAGES_PER_PAGE),
-            MESSAGES_PER_PAGE + 1);
-
-        if ($message->find()) {
-            return $message;
-        } else {
-            return null;
-        }
-    }
-
-    function getMessageList($message)
-    {
-        return new OutboxMessageList($this, $message);
-    }
-
-    /**
-     * instructions for using this page
-     *
-     * @return string localised instructions for using the page
-     */
-    function getInstructions()
-    {
-        // TRANS: Instructions for outbox.
-        return _('This is your outbox, which lists private messages you have sent.');
-    }
-}
-
-class OutboxMessageList extends MessageList
-{
-    function newItem($message)
-    {
-        return new OutboxMessageListItem($this->out, $message);
-    }
-}
-
-class OutboxMessageListItem extends MessageListItem
-{
-    /**
-     * Returns the profile we want to show with the message
-     *
-     * @return Profile The profile that matches the message
-     */
-    function getMessageProfile()
-    {
-        return $this->message->getTo();
-    }
-}
diff --git a/actions/showmessage.php b/actions/showmessage.php
deleted file mode 100644 (file)
index 86fbee8..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Show a single message
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Personal
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2008-2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-if (!defined('STATUSNET') && !defined('LACONICA')) {
-    exit(1);
-}
-
-/**
- * Show a single message
- *
- * @category Personal
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- */
-
-class ShowmessageAction extends Action
-{
-    /**
-     * Message object to show
-     */
-    var $message = null;
-
-    /**
-     * The current user
-     */
-
-    var $user = null;
-
-    /**
-     * Load attributes based on database arguments
-     *
-     * Loads all the DB stuff
-     *
-     * @param array $args $_REQUEST array
-     *
-     * @return success flag
-     */
-    function prepare($args)
-    {
-        parent::prepare($args);
-
-        $this->page = 1;
-
-        $id            = $this->trimmed('message');
-        $this->message = Message::getKV('id', $id);
-
-        if (!$this->message) {
-            // TRANS: Client error displayed requesting a single message that does not exist.
-            $this->clientError(_('No such message.'), 404);
-        }
-
-        $this->user = common_current_user();
-
-        if (empty($this->user) ||
-            ($this->user->id != $this->message->from_profile &&
-             $this->user->id != $this->message->to_profile)) {
-            // TRANS: Client error displayed requesting a single direct message the requesting user was not a party in.
-            throw new ClientException(_('Only the sender and recipient ' .
-                                        'may read this message.'), 403);
-        }
-
-        return true;
-    }
-
-    function handle($args)
-    {
-        $this->showPage();
-    }
-
-    function title()
-    {
-        if ($this->user->id == $this->message->from_profile) {
-            $to = $this->message->getTo();
-            // @todo FIXME: Might be nice if the timestamp could be localised.
-            // TRANS: Page title for single direct message display when viewing user is the sender.
-            // TRANS: %1$s is the addressed user's nickname, $2$s is a timestamp.
-            return sprintf(_('Message to %1$s on %2$s'),
-                             $to->nickname,
-                             common_exact_date($this->message->created));
-        } else if ($this->user->id == $this->message->to_profile) {
-            $from = $this->message->getFrom();
-            // @todo FIXME: Might be nice if the timestamp could be localised.
-            // TRANS: Page title for single message display.
-            // TRANS: %1$s is the sending user's nickname, $2$s is a timestamp.
-            return sprintf(_('Message from %1$s on %2$s'),
-                             $from->nickname,
-                             common_exact_date($this->message->created));
-        }
-    }
-
-
-    function showContent()
-    {
-        $this->elementStart('ul', 'notices messages');
-        $ml = new ShowMessageListItem($this, $this->message, $this->user);
-        $ml->show();
-        $this->elementEnd('ul');
-    }
-
-    function isReadOnly($args)
-    {
-        return true;
-    }
-
-    /**
-     * Don't show aside
-     *
-     * @return void
-     */
-
-    function showAside() {
-    }
-}
-
-class ShowMessageListItem extends MessageListItem
-{
-    var $user;
-
-    function __construct($out, $message, $user)
-    {
-        parent::__construct($out, $message);
-        $this->user = $user;
-    }
-
-    function getMessageProfile()
-    {
-        if ($this->user->id == $this->message->from_profile) {
-            return $this->message->getTo();
-        } else if ($this->user->id == $this->message->to_profile) {
-            return $this->message->getFrom();
-        } else {
-            // This shouldn't happen
-            return null;
-        }
-    }
-}
index c8d922a2f0f50d6ef504b73a4b8da45cecdd9210..56f61c63ab2c1453ebd8250c6c17b721bd358bcc 100644 (file)
@@ -44,7 +44,7 @@ class Conversation extends Managed_DataObject
         return array(
             'fields' => array(
                 'id' => array('type' => 'int', 'not null' => true, 'description' => 'should be set from root notice id (since 2014-03-01 commit)'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'URI of the conversation'),
+                'uri' => array('type' => 'varchar', 'not null'=>true, 'length' => 255, 'description' => 'URI of the conversation'),
                 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
             ),
@@ -63,7 +63,7 @@ class Conversation extends Managed_DataObject
      *
      * @return Conversation the new conversation DO
      */
-    static function create(Notice $notice)
+    static function create(Notice $notice, $uri=null)
     {
         if (empty($notice->id)) {
             throw new ServerException(_('Tried to create conversation for not yet inserted notice'));
@@ -71,10 +71,11 @@ class Conversation extends Managed_DataObject
         $conv = new Conversation();
         $conv->created = common_sql_now();
         $conv->id = $notice->id;
-        $conv->uri = sprintf('%s%s=%d:%s=%s',
+        $conv->uri = $uri ?: sprintf('%s%s=%d:%s=%s:%s=%x',
                              TagURI::mint(),
                              'noticeId', $notice->id,
-                             'objectType', 'thread');
+                             'objectType', 'thread',
+                             'crc32', crc32($notice->content));
         $result = $conv->insert();
 
         if ($result === false) {
diff --git a/classes/Message.php b/classes/Message.php
deleted file mode 100644 (file)
index cc605ab..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-<?php
-/**
- * Table Definition for message
- */
-require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
-
-class Message extends Managed_DataObject
-{
-    ###START_AUTOCODE
-    /* the code below is auto generated do not remove the above tag */
-
-    public $__table = 'message';                         // table name
-    public $id;                              // int(4)  primary_key not_null
-    public $uri;                             // varchar(255)  unique_key
-    public $from_profile;                    // int(4)   not_null
-    public $to_profile;                      // int(4)   not_null
-    public $content;                         // text()
-    public $rendered;                        // text()
-    public $url;                             // varchar(255)
-    public $created;                         // datetime()   not_null
-    public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
-    public $source;                          // varchar(32)
-
-    /* the code above is auto generated do not remove the tag below */
-    ###END_AUTOCODE
-
-    public static function schemaDef()
-    {
-        return array(
-            'fields' => array(
-                'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
-                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier'),
-                'from_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is from'),
-                'to_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is to'),
-                'content' => array('type' => 'text', 'description' => 'message content'),
-                'rendered' => array('type' => 'text', 'description' => 'HTML version of the content'),
-                'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
-                'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
-                'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
-                'source' => array('type' => 'varchar', 'length' => 32, 'description' => 'source of comment, like "web", "im", or "clientname"'),
-            ),
-            'primary key' => array('id'),
-            'unique keys' => array(
-                'message_uri_key' => array('uri'),
-            ),
-            'foreign keys' => array(
-                'message_from_profile_fkey' => array('profile', array('from_profile' => 'id')),
-                'message_to_profile_fkey' => array('profile', array('to_profile' => 'id')),
-            ),
-            'indexes' => array(
-                // @fixme these are really terrible indexes, since you can only sort on one of them at a time.
-                // looks like we really need a (to_profile, created) for inbox and a (from_profile, created) for outbox
-                'message_from_idx' => array('from_profile'),
-                'message_to_idx' => array('to_profile'),
-                'message_created_idx' => array('created'),
-            ),
-        );
-    }
-
-    function getFrom()
-    {
-        return Profile::getKV('id', $this->from_profile);
-    }
-
-    function getTo()
-    {
-        return Profile::getKV('id', $this->to_profile);
-    }
-
-    static function saveNew($from, $to, $content, $source) {
-        $sender = Profile::getKV('id', $from);
-
-        if (!$sender->hasRight(Right::NEWMESSAGE)) {
-            // TRANS: Client exception thrown when a user tries to send a direct message while being banned from sending them.
-            throw new ClientException(_('You are banned from sending direct messages.'));
-        }
-
-        $user = User::getKV('id', $sender->id);
-
-        $msg = new Message();
-
-        $msg->from_profile = $from;
-        $msg->to_profile = $to;
-        if ($user) {
-            // Use the sender's URL shortening options.
-            $msg->content = $user->shortenLinks($content);
-        } else {
-            $msg->content = common_shorten_links($content);
-        }
-        $msg->rendered = common_render_text($msg->content);
-        $msg->created = common_sql_now();
-        $msg->source = $source;
-
-        $result = $msg->insert();
-
-        if (!$result) {
-            common_log_db_error($msg, 'INSERT', __FILE__);
-            // TRANS: Message given when a message could not be stored on the server.
-            throw new ServerException(_('Could not insert message.'));
-        }
-
-        $orig = clone($msg);
-        $msg->uri = common_local_url('showmessage', array('message' => $msg->id));
-
-        $result = $msg->update($orig);
-
-        if (!$result) {
-            common_log_db_error($msg, 'UPDATE', __FILE__);
-            // TRANS: Message given when a message could not be updated on the server.
-            throw new ServerException(_('Could not update message with new URI.'));
-        }
-
-        return $msg;
-    }
-
-    static function maxContent()
-    {
-        $desclimit = common_config('message', 'contentlimit');
-        // null => use global limit (distinct from 0!)
-        if (is_null($desclimit)) {
-            $desclimit = common_config('site', 'textlimit');
-        }
-        return $desclimit;
-    }
-
-    static function contentTooLong($content)
-    {
-        $contentlimit = self::maxContent();
-        return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit));
-    }
-
-    function notify()
-    {
-        $from = User::getKV('id', $this->from_profile);
-        $to   = User::getKV('id', $this->to_profile);
-
-        mail_notify_message($this, $from, $to);
-    }
-
-    function getSource()
-    {
-        $ns = new Notice_source();
-        if (!empty($this->source)) {
-            switch ($this->source) {
-            case 'web':
-            case 'xmpp':
-            case 'mail':
-            case 'omb':
-            case 'system':
-            case 'api':
-                $ns->code = $this->source;
-                break;
-            default:
-                $ns = Notice_source::getKV($this->source);
-                if (!$ns) {
-                    $ns = new Notice_source();
-                    $ns->code = $this->source;
-                    $app = Oauth_application::getKV('name', $this->source);
-                    if ($app) {
-                        $ns->name = $app->name;
-                        $ns->url  = $app->source_url;
-                    }
-                }
-                break;
-            }
-        }
-        return $ns;
-    }
-
-    function asActivity()
-    {
-        $act = new Activity();
-
-        if (Event::handle('StartMessageAsActivity', array($this, &$act))) {
-
-            $act->id      = TagURI::mint(sprintf('activity:message:%d', $this->id));
-            $act->time    = strtotime($this->created);
-            $act->link    = $this->url;
-
-            $profile = Profile::getKV('id', $this->from_profile);
-
-            if (empty($profile)) {
-                throw new Exception(sprintf("Sender profile not found: %d", $this->from_profile));
-            }
-            
-            $act->actor            = $profile->asActivityObject();
-            $act->actor->extra[]   = $profile->profileInfo();
-
-            $act->verb = ActivityVerb::POST;
-
-            $act->objects[] = ActivityObject::fromMessage($this);
-
-            $ctx = new ActivityContext();
-
-            $rprofile = Profile::getKV('id', $this->to_profile);
-
-            if (empty($rprofile)) {
-                throw new Exception(sprintf("Receiver profile not found: %d", $this->to_profile));
-            }
-
-            $ctx->attention[$rprofile->getUri()] = ActivityObject::PERSON;
-
-            $act->context = $ctx;
-
-            $source = $this->getSource();
-
-            if ($source) {
-                $act->generator = ActivityObject::fromNoticeSource($source);
-            }
-
-            Event::handle('EndMessageAsActivity', array($this, &$act));
-        }
-
-        return $act;
-    }
-}
index f2a746a8449ec5f393d5057a44593b2f2a994771..62f6d1a685a9bf9fca590c01c66ee88d3c3a4fa2 100644 (file)
@@ -417,8 +417,9 @@ class Notice extends Managed_DataObject
     static function saveNew($profile_id, $content, $source, array $options=null) {
         $defaults = array('uri' => null,
                           'url' => null,
-                          'reply_to' => null,
-                          'repeat_of' => null,
+                          'conversation' => null,   // URI of conversation
+                          'reply_to' => null,       // This will override convo URI if the parent is known
+                          'repeat_of' => null,      // This will override convo URI if the repeated notice is known
                           'scope' => null,
                           'distribute' => true,
                           'object_type' => null,
@@ -600,6 +601,26 @@ class Notice extends Managed_DataObject
 
                 // Scope set below
             }
+
+            // If we don't know the reply, we might know the conversation!
+            // This will happen if a known remote user replies to an
+            // unknown remote user - within a known conversation.
+            if (empty($notice->conversation) and !empty($options['conversation'])) {
+                $conv = Conversation::getKV('uri', $options['conversation']);
+                if ($conv instanceof Conversation) {
+                    common_debug('Conversation stitched together from (probably) reply to unknown remote user. Activity creation time ('.$notice->created.') should maybe be compared to conversation creation time ('.$conv->created.').');
+                    $notice->conversation = $conv->id;
+                } else {
+                    // Conversation URI was not found, so we must create it. But we can't create it
+                    // until we have a Notice ID because of the database layout...
+                    $notice->tmp_conv_uri = $options['conversation'];
+                }
+            } else {
+                // If we're not using the attached conversation URI let's remove it
+                // so we don't mistake ourselves later, when creating our own Conversation.
+                // This implies that the notice knows which conversation it belongs to.
+                $options['conversation'] = null;
+            }
         }
 
         if (!empty($lat) && !empty($lon)) {
@@ -649,6 +670,15 @@ class Notice extends Managed_DataObject
 
             try {
                 $notice->insert();  // throws exception on failure
+                // If it's not part of a conversation, it's
+                // the beginning of a new conversation.
+                if (empty($notice->conversation)) { 
+                    $orig = clone($notice);
+                    // $act->context->conversation will be null if it was not provided
+                    $conv = Conversation::create($notice, $options['conversation']);
+                    $notice->conversation = $conv->id;
+                    $notice->update($orig);
+                }
             } catch (Exception $e) {
                 // Let's test if we managed initial insert, which would imply
                 // failing on some update-part (check 'insert()'). Delete if
@@ -656,6 +686,7 @@ class Notice extends Managed_DataObject
                 if (!empty($notice->id)) {
                     $notice->delete();
                 }
+                throw $e;
             }
         }
 
@@ -857,13 +888,21 @@ class Notice extends Managed_DataObject
 
             try {
                 $stored->insert();    // throws exception on error
+                $orig = clone($stored); // for updating later in this try clause
+
+                // If it's not part of a conversation, it's
+                // the beginning of a new conversation.
+                if (empty($stored->conversation)) {
+                    // $act->context->conversation will be null if it was not provided
+                    $conv = Conversation::create($stored, $act->context->conversation);
+                    $stored->conversation = $conv->id;
+                }
 
                 $object = null;
                 Event::handle('StoreActivityObject', array($act, $stored, $options, &$object));
                 if (empty($object)) {
                     throw new ServerException('No object from StoreActivityObject '.$stored->uri . ': '.$act->asString());
                 }
-                $orig = clone($stored);
                 $stored->object_type = ActivityUtils::resolveUri($object->getObjectType(), true);
                 $stored->update($orig);
             } catch (Exception $e) {
@@ -2380,14 +2419,6 @@ class Notice extends Managed_DataObject
             $changed = true;
         }
 
-        // If it's not part of a conversation, it's
-        // the beginning of a new conversation.
-        if (empty($this->conversation)) {
-            $conv = Conversation::create($this);
-            $this->conversation = $conv->id;
-            $changed = true;
-        }
-
         if ($changed && $this->update($orig) === false) {
             common_log_db_error($notice, 'UPDATE', __FILE__);
             // TRANS: Server exception thrown when a notice cannot be updated.
@@ -2407,31 +2438,34 @@ class Notice extends Managed_DataObject
      */
     function getSource()
     {
+        if (empty($this->source)) {
+            return false;
+        }
+
         $ns = new Notice_source();
-        if (!empty($this->source)) {
-            switch ($this->source) {
-            case 'web':
-            case 'xmpp':
-            case 'mail':
-            case 'omb':
-            case 'system':
-            case 'api':
+        switch ($this->source) {
+        case 'web':
+        case 'xmpp':
+        case 'mail':
+        case 'omb':
+        case 'system':
+        case 'api':
+            $ns->code = $this->source;
+            break;
+        default:
+            $ns = Notice_source::getKV($this->source);
+            if (!$ns) {
+                $ns = new Notice_source();
                 $ns->code = $this->source;
-                break;
-            default:
-                $ns = Notice_source::getKV($this->source);
-                if (!$ns) {
-                    $ns = new Notice_source();
-                    $ns->code = $this->source;
-                    $app = Oauth_application::getKV('name', $this->source);
-                    if ($app) {
-                        $ns->name = $app->name;
-                        $ns->url  = $app->source_url;
-                    }
+                $app = Oauth_application::getKV('name', $this->source);
+                if ($app) {
+                    $ns->name = $app->name;
+                    $ns->url  = $app->source_url;
                 }
-                break;
             }
+            break;
         }
+
         return $ns;
     }
 
index a03f53cc7d69cbdce92d38deff48caa8789cb932..00a457a5c9c2062aa9163373fddb4bc170fe65e3 100644 (file)
@@ -861,7 +861,6 @@ class Profile extends Managed_DataObject
     {
         $this->_deleteNotices();
         $this->_deleteSubscriptions();
-        $this->_deleteMessages();
         $this->_deleteTags();
         $this->_deleteBlocks();
         $this->_deleteAttentions();
@@ -937,17 +936,6 @@ class Profile extends Managed_DataObject
         $self->delete();
     }
 
-    function _deleteMessages()
-    {
-        $msg = new Message();
-        $msg->from_profile = $this->id;
-        $msg->delete();
-
-        $msg = new Message();
-        $msg->to_profile = $this->id;
-        $msg->delete();
-    }
-
     function _deleteTags()
     {
         $tag = new Profile_tag();
index c0aed1d3db835dd4c643deef9fb0134d8d21ab80..ec3fe7f736c55830358762cfb3edb753c799e8db 100644 (file)
@@ -55,7 +55,6 @@ $classes = array('Schema_version',
                  'Foreign_link',
                  'Foreign_subscription',
                  'Invitation',
-                 'Message',
                  'Profile_prefs',
                  'Profile_tag',
                  'Profile_list',
index 76e2edb7cec4cde00fd0956e28ac068c26f63266..fe11a0fc1571c3658fa38253c4073a18aa543127 100644 (file)
@@ -171,17 +171,6 @@ class AccountProfileBlock extends ProfileBlock
                         $this->out->elementEnd('li');
 
                         if ($this->profile->isLocal() && $cur->mutuallySubscribed($this->profile)) {
-
-                            // message
-
-                            $this->out->elementStart('li', 'entity_send-a-message');
-                            $this->out->element('a', array('href' => common_local_url('newmessage', array('to' => $this->user->id)),
-                                                      // TRANS: Link title for link on user profile.
-                                                      'title' => _('Send a direct message to this user.')),
-                                           // TRANS: Link text for link on user profile.
-                                           _m('BUTTON','Message'));
-                            $this->out->elementEnd('li');
-
                             // nudge
 
                             if ($this->user->email && $this->user->emailnotifynudge) {
index 6fd04c4db1709e16862475de53ad6da4c463b090..2d3930df0d85ec46207e6ff63fa9790556f3f664 100644 (file)
@@ -627,6 +627,14 @@ class Activity
             if (!empty($this->context->conversation)) {
                 $xs->element('link', array('rel' => ActivityContext::CONVERSATION,
                                            'href' => $this->context->conversation));
+                $xs->element(ActivityContext::CONVERSATION, null, $this->context->conversation);
+                /* Since we use XMLWriter we just use the previously hardcoded prefix for ostatus,
+                    otherwise we should use something like this:
+                $xs->elementNS(array(ActivityContext::OSTATUS => 'ostatus'),    // namespace
+                                'conversation',  // tag (or the element name from ActivityContext::CONVERSATION)
+                                null,   // attributes
+                                $this->context->conversation);  // content
+                */
             }
 
             foreach ($this->context->attention as $attnURI=>$type) {
index cebd72ea9078573fb53e3ab2aa22b9c8af45f716..32f15c1e9f963d8afa48d4e852b2067fafce2a44 100644 (file)
@@ -48,12 +48,14 @@ class ActivityContext
     const INREPLYTO  = 'in-reply-to';
     const REF        = 'ref';
     const HREF       = 'href';
+
+    // OStatus element names with prefixes
     const OBJECTTYPE = 'ostatus:object-type';   // FIXME: Undocumented!
+    const CONVERSATION = 'ostatus:conversation';
 
     const POINT     = 'point';
 
     const MENTIONED    = 'mentioned';
-    const CONVERSATION = 'ostatus:conversation';
 
     const ATTN_PUBLIC  = 'http://activityschema.org/collection/public';
 
@@ -72,7 +74,14 @@ class ActivityContext
 
         $this->location = $this->getLocation($element);
 
-        $this->conversation = ActivityUtils::getLink($element, self::CONVERSATION);
+        $convs = $element->getElementsByTagNameNS(self::OSTATUS, self::CONVERSATION);
+        foreach ($convs as $conv) {
+            $this->conversation = $conv->textContent;
+        }
+        if (empty($this->conversation)) {
+            // fallback to the atom:link rel="ostatus:conversation" element
+            $this->conversation = ActivityUtils::getLink($element, self::CONVERSATION);
+        }
 
         // Multiple attention links allowed
 
index b105bf21f23493c7111815de35207072efb93f4a..6a148d9dd545f709fe0483140d9202245c25a6b0 100644 (file)
@@ -594,19 +594,44 @@ abstract class ActivityHandlerPlugin extends Plugin
         $nli->showNoticeLink();
         $nli->showNoticeSource();
         $nli->showNoticeLocation();
-        $nli->showContext();
+        $nli->showPermalink();
         $nli->showRepeat();
 
         $nli->showNoticeOptions();
     }
 
+    public function onStartShowNoticeItemNotice(NoticeListItem $nli)
+    {
+        if (!$this->isMyNotice($nli->notice)) {
+            return true;
+        }
+
+        $this->showNoticeItemNotice($nli);
+
+        Event::handle('EndShowNoticeItemNotice', array($nli));
+        return false;
+    }
+
+    protected function showNoticeItemNotice(NoticeListItem $nli)
+    {
+        $nli->showNoticeTitle();
+        $nli->showAuthor();
+        $nli->showAddressees();
+        $nli->showContent();
+    }
+
     public function onStartShowNoticeContent(Notice $stored, HTMLOutputter $out, Profile $scoped=null)
     {
         if (!$this->isMyNotice($stored)) {
             return true;
         }
 
-        $out->text($stored->getContent());
+        $this->showNoticeContent($stored, $out, $scoped);
         return false;
     }
+
+    protected function showNoticeContent(Notice $stored, HTMLOutputter $out, Profile $scoped=null)
+    {
+        $out->text($stored->getContent());
+    }
 }
index 4b4c94aed917648807803656c815565bc7c0a7f0..a562f5d976914f7d7656369dc340b2800df0d919 100755 (executable)
@@ -54,7 +54,7 @@
 
     @subsection usermethods_sec User Methods
 
-    @subsection directmessagemethods_sec Direct Message Methods
+    @subsection directmessagemethods_sec Direct Message Methods (now a plugin)
 
     @subsection friendshipmethods_sec Friendship Methods
 
@@ -331,7 +331,7 @@ class ApiAction extends Action
         $source = null;
 
         $ns = $notice->getSource();
-        if ($ns) {
+        if ($ns instanceof Notice_source) {
             if (!empty($ns->name) && !empty($ns->url)) {
                 $source = '<a href="'
                    . htmlspecialchars($ns->url)
@@ -967,104 +967,6 @@ class ApiAction extends Action
         $this->elementEnd('entry');
     }
 
-    function showXmlDirectMessage($dm, $namespaces=false)
-    {
-        $attrs = array();
-        if ($namespaces) {
-            $attrs['xmlns:statusnet'] = 'http://status.net/schema/api/1/';
-        }
-        $this->elementStart('direct_message', $attrs);
-        foreach($dm as $element => $value) {
-            switch ($element) {
-            case 'sender':
-            case 'recipient':
-                $this->showTwitterXmlUser($value, $element);
-                break;
-            case 'text':
-                $this->element($element, null, common_xml_safe_str($value));
-                break;
-            default:
-                $this->element($element, null, $value);
-                break;
-            }
-        }
-        $this->elementEnd('direct_message');
-    }
-
-    function directMessageArray($message)
-    {
-        $dmsg = array();
-
-        $from_profile = $message->getFrom();
-        $to_profile = $message->getTo();
-
-        $dmsg['id'] = intval($message->id);
-        $dmsg['sender_id'] = intval($from_profile->id);
-        $dmsg['text'] = trim($message->content);
-        $dmsg['recipient_id'] = intval($to_profile->id);
-        $dmsg['created_at'] = $this->dateTwitter($message->created);
-        $dmsg['sender_screen_name'] = $from_profile->nickname;
-        $dmsg['recipient_screen_name'] = $to_profile->nickname;
-        $dmsg['sender'] = $this->twitterUserArray($from_profile, false);
-        $dmsg['recipient'] = $this->twitterUserArray($to_profile, false);
-
-        return $dmsg;
-    }
-
-    function rssDirectMessageArray($message)
-    {
-        $entry = array();
-
-        $from = $message->getFrom();
-
-        $entry['title'] = sprintf('Message from %1$s to %2$s',
-            $from->nickname, $message->getTo()->nickname);
-
-        $entry['content'] = common_xml_safe_str($message->rendered);
-        $entry['link'] = common_local_url('showmessage', array('message' => $message->id));
-        $entry['published'] = common_date_iso8601($message->created);
-
-        $taguribase = TagURI::base();
-
-        $entry['id'] = "tag:$taguribase:$entry[link]";
-        $entry['updated'] = $entry['published'];
-
-        $entry['author-name'] = $from->getBestName();
-        $entry['author-uri'] = $from->homepage;
-
-        $entry['avatar'] = $from->avatarUrl(AVATAR_STREAM_SIZE);
-        try {
-            $avatar = $from->getAvatar(AVATAR_STREAM_SIZE);
-            $entry['avatar-type'] = $avatar->mediatype;
-        } catch (Exception $e) {
-            $entry['avatar-type'] = 'image/png';
-        }
-
-        // RSS item specific
-
-        $entry['description'] = $entry['content'];
-        $entry['pubDate'] = common_date_rfc2822($message->created);
-        $entry['guid'] = $entry['link'];
-
-        return $entry;
-    }
-
-    function showSingleXmlDirectMessage($message)
-    {
-        $this->initDocument('xml');
-        $dmsg = $this->directMessageArray($message);
-        $this->showXmlDirectMessage($dmsg, true);
-        $this->endDocument('xml');
-    }
-
-    function showSingleJsonDirectMessage($message)
-    {
-        $this->initDocument('json');
-        $dmsg = $this->directMessageArray($message);
-        $this->showJsonObjects($dmsg);
-        $this->endDocument('json');
-    }
-
     function showAtomGroups($group, $title, $id, $link, $subtitle=null, $selfuri=null)
     {
         $this->initDocument('atom');
index ce02f55702e2937f823594b99aa4322563d77983..40161b7ab57c4a73cc25086961a61accd6fbd7bc 100644 (file)
@@ -82,28 +82,35 @@ class ApiAuthAction extends ApiAction
     {
         parent::prepare($args);
 
-        // NOTE: $this->auth_user has to get set in prepare(), not handle(),
-        // because subclasses do stuff with it in their prepares.
-
-        $oauthReq = $this->getOAuthRequest();
+        // NOTE: $this->scoped and $this->auth_user has to get set in
+        // prepare(), not handle(), as subclasses use them in prepares.
+
+        // Allow regular login session
+        if (common_logged_in()) {
+            $this->scoped = Profile::current();
+            $this->auth_user = $this->scoped->getUser();
+            if (!$this->auth_user->hasRight(Right::API)) {
+                // TRANS: Authorization exception thrown when a user without API access tries to access the API.
+                throw new AuthorizationException(_('Not allowed to use API.'));
+            }
+            $this->access = self::READ_WRITE;
+        } else {
+            $oauthReq = $this->getOAuthRequest();
 
-        if (!$oauthReq) {
-            if ($this->requiresAuth()) {
-                $this->checkBasicAuthUser(true);
+            if ($oauthReq instanceof OAuthRequest) {
+                $this->checkOAuthRequest($oauthReq);
             } else {
-                // Check to see if a basic auth user is there even
-                // if one's not required
-                $this->checkBasicAuthUser(false);
+                // If not using OAuth, check if there is a basic auth
+                // and require it if the current action requires it.
+                $this->checkBasicAuthUser($this->requiresAuth());
             }
-        } else {
-            $this->checkOAuthRequest($oauthReq);
-        }
 
-        // NOTE: Make sure we're scoped properly based on the auths!
-        if (isset($this->auth_user) && !empty($this->auth_user)) {
-            $this->scoped = $this->auth_user->getProfile();
-        } else {
-            $this->scoped = null;
+            // NOTE: Make sure we're scoped properly based on the auths!
+            if (isset($this->auth_user) && $this->auth_user instanceof User) {
+                $this->scoped = $this->auth_user->getProfile();
+            } else {
+                $this->scoped = null;
+            }
         }
 
         // legacy user transferral
@@ -215,7 +222,7 @@ class ApiAuthAction extends ApiAction
                         // does lots of session stuff.
                         global $_cur;
                         $_cur = $this->auth_user;
-                        Event::handle('EndSetApiUser', array($user)); 
+                        Event::handle('EndSetApiUser', array($user));
                     }
 
                     $msg = "API OAuth authentication for user '%s' (id: %d) on behalf of " .
@@ -279,17 +286,18 @@ class ApiAuthAction extends ApiAction
             header('WWW-Authenticate: Basic realm="' . $realm . '"');
 
             // show error if the user clicks 'cancel'
-            // TRANS: Client error thrown when authentication fails becaus a user clicked "Cancel".
+            // TRANS: Client error thrown when authentication fails because a user clicked "Cancel".
             $this->clientError(_('Could not authenticate you.'), 401);
 
-        } else {
+        } elseif ($required) {
+            // $this->auth_user_nickname - i.e. PHP_AUTH_USER - will have a value since it was not empty
 
             $user = common_check_user($this->auth_user_nickname,
                                       $this->auth_user_password);
 
             if (Event::handle('StartSetApiUser', array(&$user))) {
 
-                if (!empty($user)) {
+                if ($user instanceof User) {
                     if (!$user->hasRight(Right::API)) {
                         // TRANS: Authorization exception thrown when a user without API access tries to access the API.
                         throw new AuthorizationException(_('Not allowed to use API.'));
@@ -303,15 +311,21 @@ class ApiAuthAction extends ApiAction
             // By default, basic auth users have rw access
             $this->access = self::READ_WRITE;
 
-            if (empty($this->auth_user) && ($required || isset($_SERVER['PHP_AUTH_USER']))) {
+            if (!$this->auth_user instanceof User) {
                 $msg = sprintf(
                     "basic auth nickname = %s",
                     $this->auth_user_nickname
                 );
                 $this->logAuthFailure($msg);
+
+                // We must present WWW-Authenticate in accordance to HTTP status code 401
+                header('WWW-Authenticate: Basic realm="' . $realm . '"');
                 // TRANS: Client error thrown when authentication fails.
                 $this->clientError(_('Could not authenticate you.'), 401);
             }
+        } else {
+            // all get rw access for actions that don't require auth
+            $this->access = self::READ_WRITE;
         }
     }
 
index 02324280baec871a361c7700e591cb6d1c3f931b..efbcf91bfe881f8c50bcc62116d32218164024c0 100644 (file)
@@ -523,79 +523,6 @@ class WhoisCommand extends Command
     }
 }
 
-class MessageCommand extends Command
-{
-    var $other = null;
-    var $text = null;
-    function __construct($user, $other, $text)
-    {
-        parent::__construct($user);
-        $this->other = $other;
-        $this->text = $text;
-    }
-
-    function handle($channel)
-    {
-        try {
-            $other = $this->getUser($this->other)->getProfile();
-        } catch (CommandException $e) {
-            try {
-                $profile = $this->getProfile($this->other);
-            } catch (CommandException $f) {
-                throw $e;
-            }
-            // TRANS: Command exception text shown when trying to send a direct message to a remote user (a user not registered at the current server).
-            // TRANS: %s is a remote profile.
-            throw new CommandException(sprintf(_('%s is a remote profile; you can only send direct messages to users on the same server.'), $this->other));
-        }
-
-        $len = mb_strlen($this->text);
-
-        if ($len == 0) {
-            // TRANS: Command exception text shown when trying to send a direct message to another user without content.
-            $channel->error($this->user, _('No content!'));
-            return;
-        }
-
-        $this->text = $this->user->shortenLinks($this->text);
-
-        if (Message::contentTooLong($this->text)) {
-            // XXX: i18n. Needs plural support.
-            // TRANS: Message given if content is too long. %1$sd is used for plural.
-            // TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters.
-            $channel->error($this->user, sprintf(_m('Message too long - maximum is %1$d character, you sent %2$d.',
-                                                    'Message too long - maximum is %1$d characters, you sent %2$d.',
-                                                    Message::maxContent()),
-                                                 Message::maxContent(), mb_strlen($this->text)));
-            return;
-        }
-
-        if (!$other instanceof Profile) {
-            // TRANS: Error text shown when trying to send a direct message to a user that does not exist.
-            $channel->error($this->user, _('No such user.'));
-            return;
-        } else if (!$this->user->mutuallySubscribed($other)) {
-            // TRANS: Error text shown when trying to send a direct message to a user without a mutual subscription (each user must be subscribed to the other).
-            $channel->error($this->user, _('You can\'t send a message to this user.'));
-            return;
-        } else if ($this->user->id == $other->id) {
-            // TRANS: Error text shown when trying to send a direct message to self.
-            $channel->error($this->user, _('Do not send a message to yourself; just say it to yourself quietly instead.'));
-            return;
-        }
-        try {
-            $message = Message::saveNew($this->user->id, $other->id, $this->text, $channel->source());
-            $message->notify();
-            // TRANS: Message given have sent a direct message to another user.
-            // TRANS: %s is the name of the other user.
-            $channel->output($this->user, sprintf(_('Direct message to %s sent.'), $this->other));
-        } catch (Exception $e) {
-            // TRANS: Error text shown sending a direct message fails with an unknown reason.
-            $channel->error($this->user, $e->getMessage());
-        }
-    }
-}
-
 class RepeatCommand extends Command
 {
     var $other = null;
index 20e7ae1acf99cbc3e32219e394b5559713e064ae..e7d98da0255048b9786acc8506f72620f1a3aba2 100644 (file)
@@ -28,7 +28,7 @@ class CommandInterpreter
         // XXX: localise
 
         $text = preg_replace('/\s+/', ' ', trim($text));
-        list($cmd, $arg) = $this->split_arg($text);
+        list($cmd, $arg) = self::split_arg($text);
 
         // We try to support all the same commands as Twitter, see
         // http://getsatisfaction.com/twitter/topics/what_are_the_twitter_commands
@@ -55,7 +55,7 @@ class CommandInterpreter
                 break;
             case 'lose':
                 if ($arg) {
-                    list($other, $extra) = $this->split_arg($arg);
+                    list($other, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else {
@@ -88,7 +88,7 @@ class CommandInterpreter
                 break;
             case 'on':
                 if ($arg) {
-                    list($other, $extra) = $this->split_arg($arg);
+                    list($other, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else {
@@ -100,7 +100,7 @@ class CommandInterpreter
                 break;
             case 'off':
                 if ($arg) {
-                    list($other, $extra) = $this->split_arg($arg);
+                    list($other, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else {
@@ -122,7 +122,7 @@ class CommandInterpreter
                 if (!$arg) {
                     $result = null;
                 } else {
-                    list($other, $extra) = $this->split_arg($arg);
+                    list($other, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else {
@@ -134,7 +134,7 @@ class CommandInterpreter
                 if (!$arg) {
                     $result = null;
                 } else {
-                    list($other, $extra) = $this->split_arg($arg);
+                    list($other, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else {
@@ -147,7 +147,7 @@ class CommandInterpreter
                 if (!$arg) {
                     $result = null;
                 } else {
-                    list($other, $extra) = $this->split_arg($arg);
+                    list($other, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else {
@@ -160,7 +160,7 @@ class CommandInterpreter
                 if (!$arg) {
                     $result = null;
                 } else {
-                    list($other, $extra) = $this->split_arg($arg);
+                    list($other, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else {
@@ -173,31 +173,19 @@ class CommandInterpreter
                 if (!$arg) {
                     $result = null;
                 }
-                list($other, $extra) = $this->split_arg($arg);
+                list($other, $extra) = self::split_arg($arg);
                 if ($extra) {
                     $result = null;
                 } else {
                     $result = new GetCommand($user, $other);
                 }
                 break;
-            case 'd':
-            case 'dm':
-                if (!$arg) {
-                    $result = null;
-                }
-                list($other, $extra) = $this->split_arg($arg);
-                if (!$extra) {
-                    $result = null;
-                } else {
-                    $result = new MessageCommand($user, $other, $extra);
-                }
-                break;
             case 'r':
             case 'reply':
                 if (!$arg) {
                     $result = null;
                 }
-                list($other, $extra) = $this->split_arg($arg);
+                list($other, $extra) = self::split_arg($arg);
                 if (!$extra) {
                     $result = null;
                 } else {
@@ -211,7 +199,7 @@ class CommandInterpreter
                 if (!$arg) {
                     $result = null;
                 } else {
-                    list($other, $extra) = $this->split_arg($arg);
+                    list($other, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else {
@@ -223,7 +211,7 @@ class CommandInterpreter
                 if (!$arg) {
                     $result = null;
                 } else {
-                    list($other, $extra) = $this->split_arg($arg);
+                    list($other, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else {
@@ -235,7 +223,7 @@ class CommandInterpreter
                 if (!$arg) {
                     $result = null;
                 } else {
-                    list($other, $extra) = $this->split_arg($arg);
+                    list($other, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else {
@@ -254,7 +242,7 @@ class CommandInterpreter
                 if (!$arg) {
                     $result = null;
                 } else {
-                    list($other, $extra) = $this->split_arg($arg);
+                    list($other, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else {
@@ -268,7 +256,7 @@ class CommandInterpreter
                     $result = null;
                     break;
                 }
-                list($other, $tags) = $this->split_arg($arg);
+                list($other, $tags) = self::split_arg($arg);
                 if (!$tags) {
                     $result = null;
                 } else {
@@ -281,7 +269,7 @@ class CommandInterpreter
                     $result = null;
                     break;
                 }
-                list($other, $tags) = $this->split_arg($arg);
+                list($other, $tags) = self::split_arg($arg);
                 if (!$tags) {
                     $result = null;
                 } else {
@@ -292,7 +280,7 @@ class CommandInterpreter
                 if (!$arg) {
                     $result = null;
                 } else {
-                    list($word, $extra) = $this->split_arg($arg);
+                    list($word, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else if ($word == 'off') {
@@ -306,7 +294,7 @@ class CommandInterpreter
                 if (!$arg) {
                     $result = null;
                 } else {
-                    list($word, $extra) = $this->split_arg($arg);
+                    list($word, $extra) = self::split_arg($arg);
                     if ($extra) {
                         $result = null;
                     } else if ($word == 'all') {
@@ -337,7 +325,7 @@ class CommandInterpreter
     /**
      * Split arguments without triggering a PHP notice warning
      */
-    function split_arg($text)
+    static function split_arg($text)
     {
         $pieces = explode(' ', $text, 2);
         if (count($pieces) == 1) {
index 59f3cd99856f0a884fccb6d25787be43a7e6e4d8..3f4f9ab056765828c153719de6738b6c01b8d6c0 100644 (file)
@@ -303,6 +303,7 @@ $default =
                             'Bookmark' => array(),
                             'ClientSideShorten' => array(),
                             'Directory' => array(),
+                            'DirectMessage' => array(),
                             'EmailAuthentication' => array(),
                             'Event' => array(),
                             'Oembed' => array(),
index 379da9692c22d2f09a719842d06ca04d71b7f994..d597a8d40d3380ed0dde2c4464942c06730dcb46 100644 (file)
@@ -22,7 +22,7 @@ if (!defined('GNUSOCIAL')) { exit(1); }
 define('GNUSOCIAL_ENGINE', 'GNU social');
 define('GNUSOCIAL_ENGINE_URL', 'https://www.gnu.org/software/social/');
 
-define('GNUSOCIAL_BASE_VERSION', '1.1.2');
+define('GNUSOCIAL_BASE_VERSION', '1.1.3');
 define('GNUSOCIAL_LIFECYCLE', 'alpha1'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
 
 define('GNUSOCIAL_VERSION', GNUSOCIAL_BASE_VERSION . '-' . GNUSOCIAL_LIFECYCLE);
index 357ab9be5d0ac50ab35f4673d6c1df4286c3369b..0f764a72be47e32905b195f99645bbc5cac90589 100644 (file)
@@ -264,7 +264,7 @@ class ResultItem
             break;
         default:
             $ns = Notice_source::getKV($source);
-            if ($ns) {
+            if ($ns instanceof Notice_source) {
                 $source_name = '<a href="' . $ns->url . '">' . $ns->name . '</a>';
             }
             break;
index 507b9254d3a4a64732493e10d29a0025add08f04..9c3342a8cc83ed3fe2d5c45c58937ccdccccfd90 100644 (file)
@@ -148,6 +148,7 @@ function mail_to_user(&$user, $subject, $body, $headers=array(), $address=null)
     $recipients = $address;
     $profile    = $user->getProfile();
 
+    $headers['Date']    = date("r", time());
     $headers['From']    = mail_notify_from();
     $headers['To']      = $profile->getBestName() . ' <' . $address . '>';
     $headers['Subject'] = $subject;
diff --git a/lib/mailbox.php b/lib/mailbox.php
deleted file mode 100644 (file)
index 3c7281e..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * common superclass for direct messages inbox and outbox
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Message
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2008 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
-    exit(1);
-}
-
-/**
- * common superclass for direct messages inbox and outbox
- *
- * @category Message
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- * @see      InboxAction
- * @see      OutboxAction
- */
-class MailboxAction extends Action
-{
-    var $page = null;
-
-    function prepare($args)
-    {
-        parent::prepare($args);
-
-        $nickname   = common_canonical_nickname($this->arg('nickname'));
-        $this->user = User::getKV('nickname', $nickname);
-        $this->page = $this->trimmed('page');
-
-        if (!$this->page) {
-            $this->page = 1;
-        }
-
-        common_set_returnto($this->selfUrl());
-
-        return true;
-    }
-
-    /**
-     * output page based on arguments
-     *
-     * @param array $args HTTP arguments (from $_REQUEST)
-     *
-     * @return void
-     */
-    function handle($args)
-    {
-        parent::handle($args);
-
-        if (!$this->user) {
-            // TRANS: Client error displayed when trying to access a mailbox without providing a user.
-            $this->clientError(_('No such user.'), 404);
-        }
-
-        $cur = common_current_user();
-
-        if (!$cur || $cur->id != $this->user->id) {
-            // TRANS: Client error displayed when trying to access a mailbox that is not of the logged in user.
-            $this->clientError(_('Only the user can read their own mailboxes.'), 403);
-        }
-
-        $this->showPage();
-    }
-
-    function showNoticeForm()
-    {
-        $message_form = new MessageForm($this);
-        $message_form->show();
-    }
-
-    function showContent()
-    {
-        $message = $this->getMessages();
-
-        if ($message) {
-
-            $ml = $this->getMessageList($message);
-
-            $cnt = $ml->show();
-
-            $this->pagination($this->page > 1,
-                              $cnt > MESSAGES_PER_PAGE,
-                              $this->page,
-                              $this->trimmed('action'),
-                              array('nickname' => $this->user->nickname));
-        } else {
-            $this->element('p',
-                           'guide',
-                           // TRANS: Message displayed when there are no private messages in the inbox of a user.
-                           _('You have no private messages. '.
-                             'You can send private message to engage other users in conversation. '.
-                             'People can send you messages for your eyes only.'));
-        }
-    }
-
-    function getMessages()
-    {
-        return null;
-    }
-
-    function getMessageList($message)
-    {
-        return null;
-    }
-
-    /**
-     * Show the page notice
-     *
-     * Shows instructions for the page
-     *
-     * @return void
-     */
-    function showPageNotice()
-    {
-        $instr  = $this->getInstructions();
-        $output = common_markup_to_html($instr);
-
-        $this->elementStart('div', 'instructions');
-        $this->raw($output);
-        $this->elementEnd('div');
-    }
-
-    /**
-     * Mailbox actions are read only
-     *
-     * @param array $args other arguments
-     *
-     * @return boolean
-     */
-    function isReadOnly($args)
-    {
-         return true;
-    }
-
-    function showObjectNav()
-    {
-        $mm = new MailboxMenu($this);
-        $mm->show();
-    }
-}
diff --git a/lib/mailboxmenu.php b/lib/mailboxmenu.php
deleted file mode 100644 (file)
index 49e7dce..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Private mailboxes menu
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * Menu of existing mailboxes
- *
- * @category  General
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-class MailboxMenu extends Menu
-{
-    function show()
-    {
-        $cur = common_current_user();
-        $nickname = $cur->nickname;
-
-        $this->out->elementStart('ul', array('class' => 'nav'));
-
-        $this->item('inbox',
-                    array('nickname' => $nickname),
-                    // TRANS: Menu item in mailbox menu. Leads to incoming private messages.
-                    _m('MENU','Inbox'),
-                    // TRANS: Menu item title in mailbox menu. Leads to incoming private messages.
-                    _('Your incoming messages.'));
-
-        $this->item('outbox',
-                    array('nickname' => $nickname),
-                    // TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
-                    _m('MENU','Outbox'),
-                    // TRANS: Menu item title in mailbox menu. Leads to outgoing private messages.
-                    _('Your sent messages.'));
-
-        $this->out->elementEnd('ul');
-    }
-}
diff --git a/lib/messageform.php b/lib/messageform.php
deleted file mode 100644 (file)
index acd30e3..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for posting a direct message
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Form
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @author    Sarven Capadisli <csarven@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
-    exit(1);
-}
-
-require_once INSTALLDIR.'/lib/form.php';
-
-/**
- * Form for posting a direct message
- *
- * @category Form
- * @package  StatusNet
- * @author   Evan Prodromou <evan@status.net>
- * @author   Sarven Capadisli <csarven@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
- *
- * @see      HTMLOutputter
- */
-class MessageForm extends Form
-{
-    /**
-     * User to send a direct message to
-     */
-    var $to = null;
-
-    /**
-     * Pre-filled content of the form
-     */
-    var $content = null;
-
-    /**
-     * Constructor
-     *
-     * @param HTMLOutputter $out     output channel
-     * @param User          $to      user to send a message to
-     * @param string        $content content to pre-fill
-     */
-    function __construct($out=null, $to=null, $content=null)
-    {
-        parent::__construct($out);
-
-        $this->to      = $to;
-        $this->content = $content;
-    }
-
-    /**
-     * ID of the form
-     *
-     * @return string ID of the form
-     */
-    function id()
-    {
-        return 'form_notice-direct';
-    }
-
-   /**
-     * Class of the form
-     *
-     * @return string class of the form
-     */
-    function formClass()
-    {
-        return 'form_notice ajax-notice';
-    }
-
-    /**
-     * Action of the form
-     *
-     * @return string URL of the action
-     */
-    function action()
-    {
-        return common_local_url('newmessage');
-    }
-
-    /**
-     * Legend of the Form
-     *
-     * @return void
-     */
-    function formLegend()
-    {
-        // TRANS: Form legend for direct notice.
-        $this->out->element('legend', null, _('Send a direct notice'));
-    }
-
-    /**
-     * Data elements
-     *
-     * @return void
-     */
-    function formData()
-    {
-        $user = common_current_user();
-
-        $mutual_users = $user->mutuallySubscribedUsers();
-
-        $mutual = array();
-        // TRANS: Label entry in drop-down selection box in direct-message inbox/outbox.
-        // TRANS: This is the default entry in the drop-down box, doubling as instructions
-        // TRANS: and a brake against accidental submissions with the first user in the list.
-        $mutual[0] = _('Select recipient:');
-
-        while ($mutual_users->fetch()) {
-            if ($mutual_users->id != $user->id) {
-                $mutual[$mutual_users->id] = $mutual_users->nickname;
-            }
-        }
-
-        $mutual_users->free();
-        unset($mutual_users);
-
-        if (count($mutual) == 1) {
-            // TRANS: Entry in drop-down selection box in direct-message inbox/outbox when no one is available to message.
-            $mutual[0] = _('No mutual subscribers.');
-        }
-
-        // TRANS: Dropdown label in direct notice form.
-        $this->out->dropdown('to', _('To'), $mutual, null, false,
-                             ($this->to) ? $this->to->id : null);
-
-        $this->out->element('textarea', array('class' => 'notice_data-text',
-                                              'cols' => 35,
-                                              'rows' => 4,
-                                              'name' => 'content'),
-                            ($this->content) ? $this->content : '');
-
-        $contentLimit = Message::maxContent();
-
-        if ($contentLimit > 0) {
-            $this->out->element('span',
-                                array('class' => 'count'),
-                                $contentLimit);
-        }
-    }
-
-    /**
-     * Action elements
-     *
-     * @return void
-     */
-    function formActions()
-    {
-        $this->out->element('input', array('id' => 'notice_action-submit',
-                                           'class' => 'submit',
-                                           'name' => 'message_send',
-                                           'type' => 'submit',
-                                           // TRANS: Button text for sending a direct notice.
-                                           'value' => _m('Send button for sending notice', 'Send')));
-    }
-
-
-    /**
-     * Show the form
-     *
-     * Uses a recipe to output the form.
-     *
-     * @return void
-     * @see Widget::show()
-     */
-
-    function show()
-    {
-        $this->elementStart('div', 'input_forms');
-        $this->elementStart(
-            'div',
-            array(
-                'id'    => 'input_form_direct',
-                'class' => 'input_form current nonav'
-            )
-        );
-
-        parent::show();
-
-        $this->elementEnd('div');
-        $this->elementEnd('div');
-
-    }
-}
diff --git a/lib/messagelist.php b/lib/messagelist.php
deleted file mode 100644 (file)
index 0185977..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * The message list widget
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Widget
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * Message list widget
- *
- * @category  Widget
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-abstract class MessageList extends Widget
-{
-    var $message;
-
-    /**
-     * Constructor
-     *
-     * @param HTMLOutputter $out     Output context
-     * @param Message       $message Stream of messages to show
-     */
-    function __construct($out, $message)
-    {
-        parent::__construct($out);
-        $this->message = $message;
-    }
-
-    /**
-     * Show the widget
-     *
-     * Uses newItem() to create each new item.
-     *
-     * @return integer count of messages seen.
-     */
-    function show()
-    {
-            $cnt = 0;
-
-            $this->out->elementStart('div', array('id' =>'notices_primary'));
-
-            // TRANS: Header in message list.
-            $this->out->element('h2', null, _('Messages'));
-
-            $this->out->elementStart('ul', 'notices messages');
-
-            while ($this->message->fetch() && $cnt <= MESSAGES_PER_PAGE) {
-
-                $cnt++;
-
-                if ($cnt > MESSAGES_PER_PAGE) {
-                    break;
-                }
-
-                $mli = $this->newItem($this->message);
-
-                $mli->show();
-            }
-
-            $this->out->elementEnd('ul');
-
-            $this->out->elementEnd('div');
-    }
-
-    /**
-     * Create a new message item for a message
-     *
-     * @param Message $message The message to show
-     *
-     * @return MessageListItem an item to show
-     */
-    abstract function newItem($message);
-}
diff --git a/lib/messagelistitem.php b/lib/messagelistitem.php
deleted file mode 100644 (file)
index c9f4c60..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * A single list item for showing in a message list
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Widget
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * A single item in a message list
- *
- * @category  Widget
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-abstract class MessageListItem extends Widget
-{
-    var $message;
-
-    /**
-     * Constructor
-     *
-     * @param HTMLOutputter $out     Output context
-     * @param Message       $message Message to show
-     */
-    function __construct($out, $message)
-    {
-        parent::__construct($out);
-        $this->message = $message;
-    }
-
-    /**
-     * Show the widget
-     *
-     * @return void
-     */
-    function show()
-    {
-        $this->out->elementStart('li', array('class' => 'h-entry notice',
-                                             'id' => 'message-' . $this->message->id));
-
-        $profile = $this->getMessageProfile();
-
-        $this->out->elementStart('a', array('href' => $profile->profileurl,
-                                            'class' => 'p-author'));
-        $avatarUrl = $profile->avatarUrl(AVATAR_STREAM_SIZE);
-        $this->out->element('img', array('src' => $avatarUrl,
-                                         'class' => 'avatar u-photo',
-                                         'width' => AVATAR_STREAM_SIZE,
-                                         'height' => AVATAR_STREAM_SIZE,
-                                         'alt' => $profile->getBestName()));
-        $this->out->element('span', array('class' => 'nickname fn'), $profile->getNickname());
-        $this->out->elementEnd('a');
-
-        // FIXME: URL, image, video, audio
-        $this->out->elementStart('div', array('class' => 'e-content'));
-        $this->out->raw($this->message->rendered);
-        $this->out->elementEnd('div');
-
-        $messageurl = common_local_url('showmessage',
-                                       array('message' => $this->message->id));
-
-        // XXX: we need to figure this out better. Is this right?
-        if (strcmp($this->message->uri, $messageurl) != 0 &&
-            preg_match('/^http/', $this->message->uri)) {
-            $messageurl = $this->message->uri;
-        }
-
-        $this->out->elementStart('div', 'entry-metadata');
-        $this->out->elementStart('a', array('rel' => 'bookmark',
-                                            'class' => 'timestamp',
-                                            'href' => $messageurl));
-        $dt = common_date_iso8601($this->message->created);
-        $this->out->element('time', array('class' => 'dt-published',
-                                          'datetime' => common_date_iso8601($this->message->created),
-                                          // TRANS: Timestamp title (tooltip text) for NoticeListItem
-                                          'title' => common_exact_date($this->message->created)),
-                            common_date_string($this->message->created));
-        $this->out->elementEnd('a');
-
-        if ($this->message->source) {
-            $this->out->elementStart('span', 'source');
-            // FIXME: bad i18n. Device should be a parameter (from %s).
-            // TRANS: Followed by notice source (usually the client used to send the notice).
-            $this->out->text(_('from'));
-            $this->showSource($this->message->source);
-            $this->out->elementEnd('span');
-        }
-        $this->out->elementEnd('div');
-
-        $this->out->elementEnd('li');
-    }
-
-    /**
-     * Dummy method. Serves no other purpose than to make strings available used
-     * in self::showSource() through xgettext.
-     *
-     * @return void
-     */
-    function messageListItemDummyMessages()
-    {
-        // A dummy array with messages. These will get extracted by xgettext and
-        // are used in self::showSource().
-        $dummy_messages = array(
-            // TRANS: A possible notice source (web interface).
-            _m('SOURCE','web'),
-            // TRANS: A possible notice source (XMPP).
-            _m('SOURCE','xmpp'),
-            // TRANS: A possible notice source (e-mail).
-            _m('SOURCE','mail'),
-            // TRANS: A possible notice source (OpenMicroBlogging).
-            _m('SOURCE','omb'),
-            // TRANS: A possible notice source (Application Programming Interface).
-            _m('SOURCE','api'),
-        );
-    }
-
-    /**
-     * Show the source of the message
-     *
-     * Returns either the name (and link) of the API client that posted the notice,
-     * or one of other other channels.
-     *
-     * @param string $source the source of the message
-     *
-     * @return void
-     */
-    function showSource($source)
-    {
-        $source_name = _m('SOURCE',$source);
-        switch ($source) {
-        case 'web':
-        case 'xmpp':
-        case 'mail':
-        case 'omb':
-        case 'api':
-            $this->out->element('span', 'device', $source_name);
-            break;
-        default:
-            $ns = Notice_source::getKV($source);
-            if ($ns) {
-                $this->out->elementStart('span', 'device');
-                $this->out->element('a', array('href' => $ns->url,
-                                               'rel' => 'external'),
-                                    $ns->name);
-                $this->out->elementEnd('span');
-            } else {
-                $this->out->element('span', 'device', $source_name);
-            }
-            break;
-        }
-        return;
-    }
-
-    /**
-     * Return the profile to show in the message item
-     *
-     * Overridden in sub-classes to show sender, receiver, or whatever
-     *
-     * @return Profile profile to show avatar and name of
-     */
-    abstract function getMessageProfile();
-}
index e034bb9b31fbbd37530dcd0d2d137b26f44969a9..d9a00f7ee568f0166e9ce84e63e6cb54a32c1315 100644 (file)
@@ -97,11 +97,10 @@ abstract class MicroAppPlugin extends ActivityHandlerPlugin
             return true;
         }
 
-        $adapter = $this->adaptNoticeListItem($nli);
-
-        if (empty($adapter)) {
-            throw new ServerException('Could not adapt NoticeListItem');
-        }
+        // Legacy use was creating a "NoticeListItemAdapter", but
+        // nowadays we solve that using event handling for microapps.
+        // This section will remain until all plugins are fixed.
+        $adapter = $this->adaptNoticeListItem($nli) ?: $nli;
 
         $adapter->showNotice();
         $adapter->showNoticeAttachments();
index 57207339a912d9ac0ae5fbe0f504db5cbb2a1e90..8572c6583ee083c2040727f5d11557c3a23a4d17 100644 (file)
@@ -113,10 +113,13 @@ class NoticeListItem extends Widget
 
     function showNotice()
     {
-        $this->showNoticeTitle();
-        $this->showAuthor();
-        $this->showAddressees();
-        $this->showContent();
+        if (Event::handle('StartShowNoticeItemNotice', array($this))) {
+            $this->showNoticeTitle();
+            $this->showAuthor();
+            $this->showAddressees();
+            $this->showContent();
+            Event::handle('EndShowNoticeItemNotice', array($this));
+        }
     }
 
     function showNoticeTitle()
@@ -136,9 +139,7 @@ class NoticeListItem extends Widget
             $this->showNoticeLink();
             $this->showNoticeSource();
             $this->showNoticeLocation();
-            if ($this->notice->hasConversation()) {
-                $this->showContext();
-            }
+            $this->showPermalink();
             $this->showRepeat();
             Event::handle('EndShowNoticeInfo', array($this));
         }
@@ -307,8 +308,8 @@ class NoticeListItem extends Widget
     function showNoticeLink()
     {
         $this->out->elementStart('a', array('rel' => 'bookmark',
-                                            'class' => 'u-url timestamp',
-                                            'href' => $this->notice->getLocalUrl()));
+                                            'class' => 'timestamp',
+                                            'href' => Conversation::getUrlFromNotice($this->notice)));
         $this->out->element('time', array('class' => 'dt-published',
                                           'datetime' => common_date_iso8601($this->notice->created),
                                           // TRANS: Timestamp title (tooltip text) for NoticeListItem
@@ -416,65 +417,74 @@ class NoticeListItem extends Widget
     {
         $ns = $this->notice->getSource();
 
-        if ($ns) {
-            // TRANS: A possible notice source (web interface).
-            $source_name = (empty($ns->name)) ? ($ns->code ? _($ns->code) : _m('SOURCE','web')) : _($ns->name);
-            $this->out->text(' ');
-            $this->out->elementStart('span', 'source');
-            // @todo FIXME: probably i18n issue. If "from" is followed by text, that should be a parameter to "from" (from %s).
-            // TRANS: Followed by notice source.
-            $this->out->text(_('from'));
-            $this->out->text(' ');
+        if (!$ns instanceof Notice_source) {
+            return false;
+        }
 
-            $name  = $source_name;
-            $url   = $ns->url;
-            $title = null;
+        // TRANS: A possible notice source (web interface).
+        $source_name = (empty($ns->name)) ? ($ns->code ? _($ns->code) : _m('SOURCE','web')) : _($ns->name);
+        $this->out->text(' ');
+        $this->out->elementStart('span', 'source');
+        // @todo FIXME: probably i18n issue. If "from" is followed by text, that should be a parameter to "from" (from %s).
+        // TRANS: Followed by notice source.
+        $this->out->text(_('from'));
+        $this->out->text(' ');
 
-            if (Event::handle('StartNoticeSourceLink', array($this->notice, &$name, &$url, &$title))) {
-                $name = $source_name;
-                $url  = $ns->url;
-            }
-            Event::handle('EndNoticeSourceLink', array($this->notice, &$name, &$url, &$title));
+        $name  = $source_name;
+        $url   = $ns->url;
+        $title = null;
 
-            // if $ns->name and $ns->url are populated we have
-            // configured a source attr somewhere
-            if (!empty($name) && !empty($url)) {
-                $this->out->elementStart('span', 'device');
+        if (Event::handle('StartNoticeSourceLink', array($this->notice, &$name, &$url, &$title))) {
+            $name = $source_name;
+            $url  = $ns->url;
+        }
+        Event::handle('EndNoticeSourceLink', array($this->notice, &$name, &$url, &$title));
 
-                $attrs = array(
-                    'href' => $url,
-                    'rel' => 'external'
-                );
+        // if $ns->name and $ns->url are populated we have
+        // configured a source attr somewhere
+        if (!empty($name) && !empty($url)) {
+            $this->out->elementStart('span', 'device');
 
-                if (!empty($title)) {
-                    $attrs['title'] = $title;
-                }
+            $attrs = array(
+                'href' => $url,
+                'rel' => 'external'
+            );
 
-                $this->out->element('a', $attrs, $name);
-                $this->out->elementEnd('span');
-            } else {
-                $this->out->element('span', 'device', $name);
+            if (!empty($title)) {
+                $attrs['title'] = $title;
             }
 
+            $this->out->element('a', $attrs, $name);
             $this->out->elementEnd('span');
+        } else {
+            $this->out->element('span', 'device', $name);
         }
+
+        $this->out->elementEnd('span');
     }
 
     /**
-     * show link to notice this notice is a reply to
+     * show link to single-notice view for this notice item
      *
-     * If this notice is a reply, show a link to the notice it is replying to. The
-     * heavy lifting for figuring out replies happens at save time.
+     * A permalink that goes to this specific object and nothing else
      *
      * @return void
      */
-    function showContext()
+    function showPermalink()
     {
-        $this->out->element('a',
-                            array('href' => $this->notice->getConversationUrl(),
-                                  'class' => 'conversation'),
-                            // TRANS: Addition in notice list item if notice is part of a conversation.
-                            _('in context'));
+        $class = 'permalink u-url';
+        if (!$this->notice->isLocal()) {
+            $class .= ' external';
+        }
+        try {
+            $this->out->element('a',
+                        array('href' => $this->notice->getUrl(),
+                              'class' => $class),
+                        // TRANS: Addition in notice list item for single-notice view.
+                        _('permalink'));
+        } catch (InvalidUrlException $e) {
+            // no permalink available
+        }
     }
 
     /**
index 8c413c6ab951e9c2943aa1796f17f687707c79ee..06bd2474bb928292dd043496bc4ae436adc448f4 100644 (file)
@@ -96,19 +96,6 @@ class PersonalGroupNav extends Menu
                                  sprintf(_('Replies to %s'), $name),
                                  $mine && $action =='replies', 'nav_timeline_replies');
 
-
-            if ($scoped instanceof Profile && $scoped->id == $target->id &&
-                !common_config('singleuser', 'enabled')) {
-
-                $this->out->menuItem(common_local_url('inbox', array('nickname' =>
-                                                                     $nickname)),
-                                     // TRANS: Menu item in personal group navigation menu.
-                                     _m('MENU','Messages'),
-                                     // TRANS: Menu item title in personal group navigation menu.
-                                     _('Your incoming messages'),
-                                     $mine && $action =='inbox');
-            }
-
             Event::handle('EndPersonalGroupNav', array($this, $target, $scoped));
         }
         $this->out->elementEnd('ul');
index 54683e986e67977aff5a3e72fed935df4e122571..8260cb3e2e8cffa99b0290f3d346548f40a23c6a 100644 (file)
@@ -249,12 +249,6 @@ class Router
                         array('action' => 'conversation'),
                         array('id' => '[0-9]+'));
 
-            $m->connect('message/new', array('action' => 'newmessage'));
-            $m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => Nickname::DISPLAY_FMT));
-            $m->connect('message/:message',
-                        array('action' => 'showmessage'),
-                        array('message' => '[0-9]+'));
-
             $m->connect('user/:id',
                         array('action' => 'userbyid'),
                         array('id' => '[0-9]+'));
@@ -507,21 +501,6 @@ class Router
                               'screen_name' => Nickname::DISPLAY_FMT,
                               'format' => '(xml|json)'));
 
-            // direct messages
-
-            $m->connect('api/direct_messages.:format',
-                        array('action' => 'ApiDirectMessage',
-                              'format' => '(xml|json|rss|atom)'));
-
-            $m->connect('api/direct_messages/sent.:format',
-                        array('action' => 'ApiDirectMessage',
-                              'format' => '(xml|json|rss|atom)',
-                              'sent' => true));
-
-            $m->connect('api/direct_messages/new.:format',
-                        array('action' => 'ApiDirectMessageNew',
-                              'format' => '(xml|json)'));
-
             // friendships
 
             $m->connect('api/friendships/show.:format',
index b994e20296b895078722ad028fe8b36defdf507b..f8acf34f072d69b5ca8f88cbdf4b2b9c96c409f6 100644 (file)
@@ -135,11 +135,11 @@ class SearchAction extends Action
             // TRANS: Standard search suggestions shown when a search does not give any results.
             $message .= sprintf(_("You can also try your search on other engines:
 
-* [Twingly](http://www.twingly.com/search?q=%s&content=microblog&site=%%%%site.server%%%%)
-* [Tweet scan](http://www.tweetscan.com/indexi.php?s=%s)
-* [Google](http://www.google.com/search?q=site%%3A%%%%site.server%%%%+%s)
-* [Yahoo](http://search.yahoo.com/search?p=site%%3A%%%%site.server%%%%+%s)
-* [Collecta](http://collecta.com/#q=%s)"), $qe, $qe, $qe, $qe, $qe);
+* [DuckDuckGo](https://duckduckgo.com/?q=site%%3A%%%%site.server%%%%+%s)
+* [Ixquick](https://ixquick.com/do/search?query=site%%3A%%%%site.server%%%%+%s)
+* [Google](https://www.google.com/search?q=site%%3A%%%%site.server%%%%+%s)
+* [Yahoo!](https://search.yahoo.com/search?p=site%%3A%%%%site.server%%%%+%s)
+"), $qe, $qe, $qe, $qe);
             $message .= "\n";
         }
         $this->elementStart('div', 'help instructions');
index 15d286dbf97529c621e376461615881e243924d0..18d13505c8ddcde23ae79d57aa02a558c06f02de 100644 (file)
@@ -185,11 +185,6 @@ class ThreadedNoticeListItem extends NoticeListItem
         return 3;
     }
 
-    function showContext()
-    {
-        // Silence!
-    }
-
     /**
      * finish the notice
      *
@@ -299,11 +294,6 @@ class ThreadedNoticeListSubItem extends NoticeListItem
         //
     }
 
-    function showContext()
-    {
-        //
-    }
-
     function getReplyProfiles()
     {
         $all = parent::getReplyProfiles();
index 21dfff1db5be88ec3635143c63832c316b979570..a94fee21393e6414228e52abdd1528909a5f181e 100644 (file)
@@ -75,10 +75,8 @@ class UserActivityStream extends AtomUserNoticeFeed
         $subscriptions = $this->getSubscriptions();
         $subscribers   = $this->getSubscribers();
         $groups        = $this->getGroups();
-        $messagesFrom  = $this->getMessagesFrom();
-        $messagesTo    = $this->getMessagesTo();
 
-        $objs = array_merge($subscriptions, $subscribers, $groups, $notices, $messagesFrom, $messagesTo);
+        $objs = array_merge($subscriptions, $subscribers, $groups, $notices);
 
         Event::handle('AppendUserActivityStreamObjects', array($this, &$objs));
 
@@ -353,32 +351,6 @@ class UserActivityStream extends AtomUserNoticeFeed
         return $groups;
     }
 
-    function getMessagesTo()
-    {
-        $msgMap = Message::listGet('to_profile', array($this->user->id));
-
-        $messages = $msgMap[$this->user->id];
-
-        if (!empty($this->after)) {
-            $messages = array_filter($messages, array($this, 'createdAfter'));
-        }
-
-        return $messages;
-    }
-
-    function getMessagesFrom()
-    {
-        $msgMap = Message::listGet('from_profile', array($this->user->id));
-
-        $messages = $msgMap[$this->user->id];
-
-        if (!empty($this->after)) {
-            $messages = array_filter($messages, array($this, 'createdAfter'));
-        }
-
-        return $messages;
-    }
-
     function createdAfter($item) {
         $created = strtotime((empty($item->created)) ? $item->modified : $item->created);
         return ($created >= $this->after);
index 08a0cdea2fac9f736e164ac0e01e0a3f1bccd2c9..e18e1991ff5f3c2df0c470a6b3d79866fbc78a2a 100644 (file)
@@ -1261,6 +1261,7 @@ function common_path($relative, $ssl=false, $addSession=true)
     $pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : '';
 
     if (($ssl && (common_config('site', 'ssl') === 'sometimes'))
+        || StatusNet::isHTTPS()
         || common_config('site', 'ssl') === 'always') {
         $proto = 'https';
         if (is_string(common_config('site', 'sslserver')) &&
index 528f633050570c54b939ebed2b73f513a9a63d10..481b2dedcabc8b80c3185ea12a61d976d38c1b61 100644 (file)
@@ -142,6 +142,15 @@ class XMLOutputter
         $this->elementEnd($tag);
     }
 
+    function elementNS(array $ns, $tag, $attrs=null, $content=null)
+    {
+        $this->elementStartNS($ns, $tag, $attrs);
+        if (!is_null($content)) {
+            $this->xw->text($content);
+        }
+        $this->elementEnd($tag);
+    }
+
     /**
      * output a start tag for an element
      *
@@ -169,6 +178,20 @@ class XMLOutputter
         }
     }
 
+    function elementStartNS(array $ns, $tag, $attrs=null)
+    {
+        reset($ns); // array pointer to 0
+        $uri = key($ns);
+        $this->xw->startElementNS($ns[$uri], $tag, $uri);
+        if (is_array($attrs)) {
+            foreach ($attrs as $name => $value) {
+                $this->xw->writeAttribute($name, $value);
+            }
+        } else if (is_string($attrs)) {
+            $this->xw->writeAttribute('class', $attrs);
+        }
+    }
+
     /**
      * output an end tag for an element
      *
index 3dea569dfff312555c34c54e4d614bdb44fb44c5..c4edce74e85ba5dbc07ee6c441d7a03067c43e00 100644 (file)
@@ -43,10 +43,10 @@ class AccountManagerPlugin extends Plugin
     /**
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      * @return boolean hook return
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         // Discovery actions
         $m->connect('main/amcd.json',
index 70d927900dbda4d40ddfbde9af158e2526a81b44..a3974b3a7879a46d2103388e3236336537d6040b 100644 (file)
@@ -175,12 +175,12 @@ class ActivitySpamPlugin extends Plugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
 
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('main/train/spam',
                     array('action' => 'train', 'category' => 'spam'));
index 2286d1da3d5cc3ab8d2edb6550358266297cc3b6..d4d56c1be2bf5970a9a5d3e79e1e78610ff4f062 100644 (file)
@@ -162,10 +162,10 @@ class BitlyUrlPlugin extends UrlShortenerPlugin
     /**
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      * @return boolean hook return
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('panel/bitly',
                     array('action' => 'bitlyadminpanel'));
index 4e1b030893b23e117118bafc6391ca58bf7a80cc..fc26cd77c631e63a21351005408a1555e133a2cd 100644 (file)
@@ -274,11 +274,11 @@ class BlacklistPlugin extends Plugin
     /**
      * Add our actions to the URL router
      *
-     * @param Net_URL_Mapper $m URL mapper for this hit
+     * @param URLMapper $m URL mapper for this hit
      *
      * @return boolean hook return
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('panel/blacklist', array('action' => 'blacklistadminpanel'));
         return true;
index f6b702376b9ab8c4337dacaf1abda6c2a5ac9ae0..8d5532b8b17c508c1cce18f1960c20aaf07e7a9c 100644 (file)
@@ -77,11 +77,11 @@ class BlogPlugin extends MicroAppPlugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('blog/new',
                     array('action' => 'newblogentry'));
index fdd3c359b866fa7d3a8289680af26e470788590a..9ea83c4caf1f2263f43ff3952b5e550093b585fc 100644 (file)
@@ -109,11 +109,11 @@ class BookmarkPlugin extends MicroAppPlugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         if (common_config('singleuser', 'enabled')) {
             $nickname = User::singleUserNickname();
@@ -440,19 +440,6 @@ class BookmarkPlugin extends MicroAppPlugin
         return $object;
     }
 
-    /**
-     * Given a notice list item, returns an adapter specific
-     * to this plugin.
-     *
-     * @param NoticeListItem $nli item to adapt
-     *
-     * @return NoticeListItemAdapter adapter or null
-     */
-    function adaptNoticeListItem($nli)
-    {
-        return new BookmarkListItem($nli);
-    }
-
     function entryForm($out)
     {
         return new InitialBookmarkForm($out);
@@ -505,4 +492,87 @@ class BookmarkPlugin extends MicroAppPlugin
 
         return true;
     }
+
+    protected function showNoticeItemNotice(NoticeListItem $nli)
+    {
+        $nli->out->elementStart('div', 'entry-title');
+        $nli->showAuthor();
+        $nli->showContent();
+        $nli->out->elementEnd('div');
+    }
+
+    protected function showNoticeContent(Notice $stored, HTMLOutputter $out, Profile $scoped=null)
+    {
+        $nb = Bookmark::getByNotice($stored);
+
+        if (empty($nb)) {
+            common_log(LOG_ERR, "No bookmark for notice {$stored->id}");
+            parent::showContent();
+            return;
+        } else if (empty($nb->url)) {
+            common_log(LOG_ERR, "No url for bookmark {$nb->id} for notice {$stored->id}");
+            parent::showContent();
+            return;
+        }
+
+        $profile = $stored->getProfile();
+
+        // Whether to nofollow
+        $attrs = array('href' => $nb->url, 'class' => 'bookmark-title');
+
+        $nf = common_config('nofollow', 'external');
+
+        if ($nf == 'never' || ($nf == 'sometimes' and $out instanceof ShowstreamAction)) {
+            $attrs['rel'] = 'external';
+        } else {
+            $attrs['rel'] = 'nofollow external';
+        }
+
+        $out->elementStart('h3');
+        $out->element('a', $attrs, $nb->title);
+        $out->elementEnd('h3');
+
+        // Replies look like "for:" tags
+        $replies = $stored->getReplies();
+        $tags = $stored->getTags();
+
+        if (!empty($replies) || !empty($tags)) {
+
+            $out->elementStart('ul', array('class' => 'bookmark-tags'));
+
+            foreach ($replies as $reply) {
+                $other = Profile::getKV('id', $reply);
+                if (!empty($other)) {
+                    $out->elementStart('li');
+                    $out->element('a', array('rel' => 'tag',
+                                             'href' => $other->profileurl,
+                                             'title' => $other->getBestName()),
+                                  sprintf('for:%s', $other->nickname));
+                    $out->elementEnd('li');
+                    $out->text(' ');
+                }
+            }
+
+            foreach ($tags as $tag) {
+                $tag = trim($tag);
+                if (!empty($tag)) {
+                    $out->elementStart('li');
+                    $out->element('a',
+                                  array('rel' => 'tag',
+                                        'href' => Notice_tag::url($tag)),
+                                  $tag);
+                    $out->elementEnd('li');
+                    $out->text(' ');
+                }
+            }
+
+            $out->elementEnd('ul');
+        }
+
+        if (!empty($nb->description)) {
+            $out->element('p',
+                          array('class' => 'bookmark-description'),
+                          $nb->description);
+        }
+    }
 }
diff --git a/plugins/Bookmark/lib/bookmarklistitem.php b/plugins/Bookmark/lib/bookmarklistitem.php
deleted file mode 100644 (file)
index 118800a..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Adapter to show bookmarks in a nicer way
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Bookmark
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * An adapter to show bookmarks in a nicer way
- *
- * @category  Bookmark
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-class BookmarkListItem extends NoticeListItemAdapter
-{
-    function showNotice()
-    {
-        $this->nli->out->elementStart('div', 'entry-title');
-        $this->nli->showAuthor();
-        $this->showContent();
-        $this->nli->out->elementEnd('div');
-    }
-
-    function showContent()
-    {
-        $notice = $this->nli->notice;
-        $out    = $this->nli->out;
-
-        $nb = Bookmark::getByNotice($notice);
-
-        if (empty($nb)) {
-            common_log(LOG_ERR, "No bookmark for notice {$notice->id}");
-            parent::showContent();
-            return;
-        } else if (empty($nb->url)) {
-            common_log(LOG_ERR, "No url for bookmark {$nb->id} for notice {$notice->id}");
-            parent::showContent();
-            return;
-        }
-
-        $profile = $notice->getProfile();
-
-        $out->elementStart('div', array('class' => 'e-content'));
-
-        // Whether to nofollow
-
-        $attrs = array('href' => $nb->url,
-                       'class' => 'bookmark-title');
-
-        $nf = common_config('nofollow', 'external');
-
-        if ($nf == 'never' || ($nf == 'sometimes' and $out instanceof ShowstreamAction)) {
-            $attrs['rel'] = 'external';
-        } else {
-            $attrs['rel'] = 'nofollow external';
-        }
-
-        $out->elementStart('h3');
-        $out->element('a',
-                      $attrs,
-                      $nb->title);
-        $out->elementEnd('h3');
-
-        // Replies look like "for:" tags
-
-        $replies = $notice->getReplies();
-        $tags = $notice->getTags();
-
-        if (!empty($replies) || !empty($tags)) {
-
-            $out->elementStart('ul', array('class' => 'bookmark-tags'));
-
-            foreach ($replies as $reply) {
-                $other = Profile::getKV('id', $reply);
-                if (!empty($other)) {
-                    $out->elementStart('li');
-                    $out->element('a', array('rel' => 'tag',
-                                             'href' => $other->profileurl,
-                                             'title' => $other->getBestName()),
-                                  sprintf('for:%s', $other->nickname));
-                    $out->elementEnd('li');
-                    $out->text(' ');
-                }
-            }
-
-            foreach ($tags as $tag) {
-                $tag = trim($tag);
-                if (!empty($tag)) {
-                    $out->elementStart('li');
-                    $out->element('a',
-                                  array('rel' => 'tag',
-                                        'href' => Notice_tag::url($tag)),
-                                  $tag);
-                    $out->elementEnd('li');
-                    $out->text(' ');
-                }
-            }
-
-            $out->elementEnd('ul');
-        }
-
-        if (!empty($nb->description)) {
-            $out->element('p',
-                          array('class' => 'bookmark-description'),
-                          $nb->description);
-        }
-
-        $out->elementEnd('div');
-    }
-}
index d7db04e1ddce05004231c741bc02a920efbe5e82..65911dfc48abff943a1a6454b6be0e38c30c0da7 100644 (file)
@@ -69,18 +69,6 @@ class ConversationTreeItem extends NoticeListItem
         return;
     }
 
-    /**
-     * show link to notice conversation page
-     *
-     * Since we're only used on the conversation page, we skip this
-     *
-     * @return void
-     */
-    function showContext()
-    {
-        return;
-    }
-
     /**
      * show people this notice is in reply to
      *
diff --git a/plugins/DirectMessage/DirectMessagePlugin.php b/plugins/DirectMessage/DirectMessagePlugin.php
new file mode 100644 (file)
index 0000000..f24c043
--- /dev/null
@@ -0,0 +1,172 @@
+<?php
+/*
+ * GNU Social - a federating social network
+ * Copyright (C) 2014, Free Software Foundation, 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('GNUSOCIAL')) { exit(1); }
+
+/**
+ * @maintainer  Mikael Nordfeldth <mmn@hethane.se>
+ */
+class DirectMessagePlugin extends Plugin
+{
+    public function onCheckSchema()
+    {
+        $schema = Schema::get();
+        $schema->ensureTable('message', Message::schemaDef());
+        return true;
+    }
+
+    public function onRouterInitialized(URLMapper $m)
+    {
+        // web front-end actions
+        $m->connect('message/new', array('action' => 'newmessage'));
+        $m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => Nickname::DISPLAY_FMT));
+        $m->connect('message/:message',
+                    array('action' => 'showmessage'),
+                    array('message' => '[0-9]+'));
+
+        // direct messages
+        $m->connect('api/direct_messages.:format',
+                    array('action' => 'ApiDirectMessage',
+                          'format' => '(xml|json|rss|atom)'));
+        $m->connect('api/direct_messages/sent.:format',
+                    array('action' => 'ApiDirectMessage',
+                          'format' => '(xml|json|rss|atom)',
+                          'sent' => true));
+        $m->connect('api/direct_messages/new.:format',
+                    array('action' => 'ApiDirectMessageNew',
+                          'format' => '(xml|json)'));
+
+        return true;
+    }
+
+    public function onAppendUserActivityStreamObjects(UserActivityStream $uas, array &$objs)
+    {
+        // Messages _from_ the user
+        $msgMap = Message::listGet('from_profile', array($this->user->id));
+        $messages = $msgMap[$uas->user->id];
+        if (!empty($uas->after)) {
+            $messages = array_filter($messages, array($uas, 'createdAfter'));
+        }
+        $objs[] = $messages;
+
+        // Messages _to_ the user
+        $msgMap = Message::listGet('to_profile', array($this->user->id));
+        $messages = $msgMap[$uas->user->id];
+        if (!empty($uas->after)) {
+            $messages = array_filter($messages, array($uas, 'createdAfter'));
+        }
+        $objs[] = $messages;
+
+        return true;
+    }
+
+    /**
+     * Are we allowed to perform a certain command over the API?
+     */
+    public function onCommandSupportedAPI(Command $cmd, &$supported)
+    {
+        $supported = $supported || $cmd instanceof MessageCommand;
+        return true;
+    }
+
+    /**
+     * EndInterpretCommand will handle the 'd' and 'dm' commands.
+     *
+     * @param string  $cmd     Command being run
+     * @param string  $arg     Rest of the message (including address)
+     * @param User    $user    User sending the message
+     * @param Command &$result The resulting command object to be run.
+     *
+     * @return boolean hook value
+     */
+    public function onStartInterpretCommand($cmd, $arg, $user, &$result)
+    {
+        $dm_cmds = array('d', 'dm');
+
+        if ($result === false && in_array($cmd, $dm_cmds)) {
+            if (!empty($arg)) {
+                list($other, $extra) = CommandInterpreter::split_arg($arg);
+                if (!empty($extra)) {
+                    $result = new MessageCommand($user, $other, $extra);
+                }
+            }
+            return false;
+        }
+        return true;
+    }
+
+    public function onEndPersonalGroupNav(Menu $menu, Profile $target, Profile $scoped=null)
+    {
+        if ($scoped instanceof Profile && $scoped->id == $target->id
+                && !common_config('singleuser', 'enabled')) {
+
+            $menu->out->menuItem(common_local_url('inbox', array('nickname' =>
+                                                                 $target->getNickname())),
+                                 // TRANS: Menu item in personal group navigation menu.
+                                 _m('MENU','Messages'),
+                                 // TRANS: Menu item title in personal group navigation menu.
+                                 _('Your incoming messages'),
+                                 $scoped->id === $target->id && $menu->actionName =='inbox');
+        }
+    }
+
+    public function onEndProfilePageActionsElements(HTMLOutputter $out, Profile $profile)
+    {
+        $scoped = Profile::current();
+        if (!$scoped instanceof Profile) {
+            return true;
+        }
+
+        if ($profile->isLocal() && $scoped->mutuallySubscribed($profile)) {
+            $out->elementStart('li', 'entity_send-a-message');
+            $out->element('a', array('href' => common_local_url('newmessage', array('to' => $profile->id)),
+                                     // TRANS: Link title for link on user profile.
+                                     'title' => _('Send a direct message to this user.')),
+                                // TRANS: Link text for link on user profile.
+                                _m('BUTTON','Message'));
+            $out->elementEnd('li');
+        }
+        return true;
+    }
+
+    public function onProfileDeleteRelated(Profile $profile, &$related)
+    {
+        $msg = new Message();
+        $msg->from_profile = $profile->id;
+        $msg->delete();
+
+        $msg = new Message();
+        $msg->to_profile = $profile->id;
+        $msg->delete();
+        return true;
+    }
+
+    public function onPluginVersion(array &$versions)
+    {
+        $versions[] = array('name' => 'Direct Message',
+                            'version' => GNUSOCIAL_VERSION,
+                            'author' => 'Mikael Nordfeldth',
+                            'homepage' => 'http://gnu.io/',
+                            'rawdescription' =>
+                            // TRANS: Plugin description.
+                            _m('Direct Message to other local users (broken out of core).'));
+
+        return true;
+    }
+}
diff --git a/plugins/DirectMessage/actions/apidirectmessage.php b/plugins/DirectMessage/actions/apidirectmessage.php
new file mode 100644 (file)
index 0000000..c18559f
--- /dev/null
@@ -0,0 +1,463 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a the direct messages from or to a user
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  API
+ * @package   StatusNet
+ * @author    Adrian Lang <mail@adrianlang.de>
+ * @author    Evan Prodromou <evan@status.net>
+ * @author    Robin Millette <robin@millette.info>
+ * @author    Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Show a list of direct messages from or to the authenticating user
+ *
+ * @category API
+ * @package  StatusNet
+ * @author   Adrian Lang <mail@adrianlang.de>
+ * @author   Evan Prodromou <evan@status.net>
+ * @author   Robin Millette <robin@millette.info>
+ * @author   Zach Copley <zach@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ */
+class ApiDirectMessageAction extends ApiAuthAction
+{
+    var $messages     = null;
+    var $title        = null;
+    var $subtitle     = null;
+    var $link         = null;
+    var $selfuri_base = null;
+    var $id           = null;
+
+    /**
+     * Take arguments for running
+     *
+     * @param array $args $_REQUEST args
+     *
+     * @return boolean success flag
+     */
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $this->user = $this->auth_user;
+
+        if (empty($this->user)) {
+            // TRANS: Client error given when a user was not found (404).
+            $this->clientError(_('No such user.'), 404);
+        }
+
+        $server   = common_root_url();
+        $taguribase = TagURI::base();
+
+        if ($this->arg('sent')) {
+
+            // Action was called by /api/direct_messages/sent.format
+
+            $this->title = sprintf(
+                // TRANS: Title. %s is a user nickname.
+                _("Direct messages from %s"),
+                $this->user->nickname
+            );
+            $this->subtitle = sprintf(
+                // TRANS: Subtitle. %s is a user nickname.
+                _("All the direct messages sent from %s"),
+                $this->user->nickname
+            );
+            $this->link = $server . $this->user->nickname . '/outbox';
+            $this->selfuri_base = common_root_url() . 'api/direct_messages/sent';
+            $this->id = "tag:$taguribase:SentDirectMessages:" . $this->user->id;
+        } else {
+            $this->title = sprintf(
+                // TRANS: Title. %s is a user nickname.
+                _("Direct messages to %s"),
+                $this->user->nickname
+            );
+            $this->subtitle = sprintf(
+                // TRANS: Subtitle. %s is a user nickname.
+                _("All the direct messages sent to %s"),
+                $this->user->nickname
+            );
+            $this->link = $server . $this->user->nickname . '/inbox';
+            $this->selfuri_base = common_root_url() . 'api/direct_messages';
+            $this->id = "tag:$taguribase:DirectMessages:" . $this->user->id;
+        }
+
+        $this->messages = $this->getMessages();
+
+        return true;
+    }
+
+    /**
+     * Handle the request
+     *
+     * Show the messages
+     *
+     * @param array $args $_REQUEST data (unused)
+     *
+     * @return void
+     */
+    function handle($args)
+    {
+        parent::handle($args);
+        $this->showMessages();
+    }
+
+    /**
+     * Show the messages
+     *
+     * @return void
+     */
+    function showMessages()
+    {
+        switch($this->format) {
+        case 'xml':
+            $this->showXmlDirectMessages();
+            break;
+        case 'rss':
+            $this->showRssDirectMessages();
+            break;
+        case 'atom':
+            $this->showAtomDirectMessages();
+            break;
+        case 'json':
+            $this->showJsonDirectMessages();
+            break;
+        default:
+            // TRANS: Client error displayed when coming across a non-supported API method.
+            $this->clientError(_('API method not found.'), $code = 404);
+            break;
+        }
+    }
+
+    /**
+     * Get notices
+     *
+     * @return array notices
+     */
+    function getMessages()
+    {
+        $message  = new Message();
+
+        if ($this->arg('sent')) {
+            $message->from_profile = $this->user->id;
+        } else {
+            $message->to_profile = $this->user->id;
+        }
+
+        if (!empty($this->max_id)) {
+            $message->whereAdd('id <= ' . $this->max_id);
+        }
+
+        if (!empty($this->since_id)) {
+            $message->whereAdd('id > ' . $this->since_id);
+        }
+
+        $message->orderBy('created DESC, id DESC');
+        $message->limit((($this->page - 1) * $this->count), $this->count);
+        $message->find();
+
+        $messages = array();
+
+        while ($message->fetch()) {
+            $messages[] = clone($message);
+        }
+
+        return $messages;
+    }
+
+    /**
+     * Is this action read only?
+     *
+     * @param array $args other arguments
+     *
+     * @return boolean true
+     */
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    /**
+     * When was this notice last modified?
+     *
+     * @return string datestamp of the latest notice in the stream
+     */
+    function lastModified()
+    {
+        if (!empty($this->messages)) {
+            return strtotime($this->messages[0]->created);
+        }
+
+        return null;
+    }
+
+    // BEGIN import from lib/apiaction.php
+
+    function showSingleXmlDirectMessage($message)
+    {
+        $this->initDocument('xml');
+        $dmsg = $this->directMessageArray($message);
+        $this->showXmlDirectMessage($dmsg, true);
+        $this->endDocument('xml');
+    }
+
+    function showSingleJsonDirectMessage($message)
+    {
+        $this->initDocument('json');
+        $dmsg = $this->directMessageArray($message);
+        $this->showJsonObjects($dmsg);
+        $this->endDocument('json');
+    }
+
+    function showXmlDirectMessage($dm, $namespaces=false)
+    {
+        $attrs = array();
+        if ($namespaces) {
+            $attrs['xmlns:statusnet'] = 'http://status.net/schema/api/1/';
+        }
+        $this->elementStart('direct_message', $attrs);
+        foreach($dm as $element => $value) {
+            switch ($element) {
+            case 'sender':
+            case 'recipient':
+                $this->showTwitterXmlUser($value, $element);
+                break;
+            case 'text':
+                $this->element($element, null, common_xml_safe_str($value));
+                break;
+            default:
+                $this->element($element, null, $value);
+                break;
+            }
+        }
+        $this->elementEnd('direct_message');
+    }
+
+    function directMessageArray($message)
+    {
+        $dmsg = array();
+
+        $from_profile = $message->getFrom();
+        $to_profile = $message->getTo();
+
+        $dmsg['id'] = intval($message->id);
+        $dmsg['sender_id'] = intval($from_profile->id);
+        $dmsg['text'] = trim($message->content);
+        $dmsg['recipient_id'] = intval($to_profile->id);
+        $dmsg['created_at'] = $this->dateTwitter($message->created);
+        $dmsg['sender_screen_name'] = $from_profile->nickname;
+        $dmsg['recipient_screen_name'] = $to_profile->nickname;
+        $dmsg['sender'] = $this->twitterUserArray($from_profile, false);
+        $dmsg['recipient'] = $this->twitterUserArray($to_profile, false);
+
+        return $dmsg;
+    }
+
+    function rssDirectMessageArray($message)
+    {
+        $entry = array();
+
+        $from = $message->getFrom();
+
+        $entry['title'] = sprintf('Message from %1$s to %2$s',
+            $from->nickname, $message->getTo()->nickname);
+
+        $entry['content'] = common_xml_safe_str($message->rendered);
+        $entry['link'] = common_local_url('showmessage', array('message' => $message->id));
+        $entry['published'] = common_date_iso8601($message->created);
+
+        $taguribase = TagURI::base();
+
+        $entry['id'] = "tag:$taguribase:$entry[link]";
+        $entry['updated'] = $entry['published'];
+
+        $entry['author-name'] = $from->getBestName();
+        $entry['author-uri'] = $from->homepage;
+
+        $entry['avatar'] = $from->avatarUrl(AVATAR_STREAM_SIZE);
+        try {
+            $avatar = $from->getAvatar(AVATAR_STREAM_SIZE);
+            $entry['avatar-type'] = $avatar->mediatype;
+        } catch (Exception $e) {
+            $entry['avatar-type'] = 'image/png';
+        }
+
+        // RSS item specific
+
+        $entry['description'] = $entry['content'];
+        $entry['pubDate'] = common_date_rfc2822($message->created);
+        $entry['guid'] = $entry['link'];
+
+        return $entry;
+    }
+
+    // END import from lib/apiaction.php
+
+    /**
+     * Shows a list of direct messages as Twitter-style XML array
+     *
+     * @return void
+     */
+    function showXmlDirectMessages()
+    {
+        $this->initDocument('xml');
+        $this->elementStart('direct-messages', array('type' => 'array',
+                                                     'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
+
+        foreach ($this->messages as $m) {
+            $dm_array = $this->directMessageArray($m);
+            $this->showXmlDirectMessage($dm_array);
+        }
+
+        $this->elementEnd('direct-messages');
+        $this->endDocument('xml');
+    }
+
+    /**
+     * Shows a list of direct messages as a JSON encoded array
+     *
+     * @return void
+     */
+    function showJsonDirectMessages()
+    {
+        $this->initDocument('json');
+
+        $dmsgs = array();
+
+        foreach ($this->messages as $m) {
+            $dm_array = $this->directMessageArray($m);
+            array_push($dmsgs, $dm_array);
+        }
+
+        $this->showJsonObjects($dmsgs);
+        $this->endDocument('json');
+    }
+
+    /**
+     * Shows a list of direct messages as RSS items
+     *
+     * @return void
+     */
+    function showRssDirectMessages()
+    {
+        $this->initDocument('rss');
+
+        $this->element('title', null, $this->title);
+
+        $this->element('link', null, $this->link);
+        $this->element('description', null, $this->subtitle);
+        $this->element('language', null, 'en-us');
+
+        $this->element(
+            'atom:link',
+            array(
+                'type' => 'application/rss+xml',
+                'href' => $this->selfuri_base . '.rss',
+                'rel' => self
+                ),
+            null
+        );
+        $this->element('ttl', null, '40');
+
+        foreach ($this->messages as $m) {
+            $entry = $this->rssDirectMessageArray($m);
+            $this->showTwitterRssItem($entry);
+        }
+
+        $this->endTwitterRss();
+    }
+
+    /**
+     * Shows a list of direct messages as Atom entries
+     *
+     * @return void
+     */
+    function showAtomDirectMessages()
+    {
+        $this->initDocument('atom');
+
+        $this->element('title', null, $this->title);
+        $this->element('id', null, $this->id);
+
+        $selfuri = common_root_url() . 'api/direct_messages.atom';
+
+        $this->element(
+            'link', array(
+            'href' => $this->link,
+            'rel' => 'alternate',
+            'type' => 'text/html'),
+            null
+        );
+        $this->element(
+            'link', array(
+            'href' => $this->selfuri_base . '.atom', 'rel' => 'self',
+            'type' => 'application/atom+xml'),
+            null
+        );
+        $this->element('updated', null, common_date_iso8601('now'));
+        $this->element('subtitle', null, $this->subtitle);
+
+        foreach ($this->messages as $m) {
+            $entry = $this->rssDirectMessageArray($m);
+            $this->showTwitterAtomEntry($entry);
+        }
+
+        $this->endDocument('atom');
+    }
+
+    /**
+     * An entity tag for this notice
+     *
+     * Returns an Etag based on the action name, language, and
+     * timestamps of the notice
+     *
+     * @return string etag
+     */
+    function etag()
+    {
+        if (!empty($this->messages)) {
+
+            $last = count($this->messages) - 1;
+
+            return '"' . implode(
+                ':',
+                array($this->arg('action'),
+                      common_user_cache_hash($this->auth_user),
+                      common_language(),
+                      strtotime($this->messages[0]->created),
+                      strtotime($this->messages[$last]->created)
+                )
+            )
+            . '"';
+        }
+
+        return null;
+    }
+}
diff --git a/plugins/DirectMessage/actions/apidirectmessagenew.php b/plugins/DirectMessage/actions/apidirectmessagenew.php
new file mode 100644 (file)
index 0000000..653fa3a
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Send a direct message via the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  API
+ * @package   StatusNet
+ * @author    Adrian Lang <mail@adrianlang.de>
+ * @author    Evan Prodromou <evan@status.net>
+ * @author    Robin Millette <robin@millette.info>
+ * @author    Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Creates a new direct message from the authenticating user to
+ * the user specified by id.
+ *
+ * @category API
+ * @package  StatusNet
+ * @author   Adrian Lang <mail@adrianlang.de>
+ * @author   Evan Prodromou <evan@status.net>
+ * @author   Robin Millette <robin@millette.info>
+ * @author   Zach Copley <zach@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ */
+class ApiDirectMessageNewAction extends ApiAuthAction
+{
+    protected $needPost = true;
+
+    var $other   = null;    // Profile we're sending to
+    var $content = null;
+
+    /**
+     * Take arguments for running
+     *
+     * @param array $args $_REQUEST args
+     *
+     * @return boolean success flag
+     */
+    protected function prepare(array $args=array())
+    {
+        parent::prepare($args);
+
+        if (empty($this->user)) {
+            // TRANS: Client error when user not found for an API direct message action.
+            $this->clientError(_('No such user.'), 404);
+        }
+
+        $this->content = $this->trimmed('text');
+
+        $user_param  = $this->trimmed('user');
+        $user_id     = $this->arg('user_id');
+        $screen_name = $this->trimmed('screen_name');
+
+        if (isset($user_param) || isset($user_id) || isset($screen_name)) {
+            $this->other = $this->getTargetProfile($user_param);
+        }
+
+        return true;
+    }
+
+    /**
+     * Handle the request
+     *
+     * Save the new message
+     *
+     * @return void
+     */
+    protected function handle()
+    {
+        parent::handle();
+
+        if (empty($this->content)) {
+            // TRANS: Client error displayed when no message text was submitted (406).
+            $this->clientError(_('No message text!'), 406);
+        } else {
+            $content_shortened = $this->auth_user->shortenLinks($this->content);
+            if (Message::contentTooLong($content_shortened)) {
+                // TRANS: Client error displayed when message content is too long.
+                // TRANS: %d is the maximum number of characters for a message.
+                $this->clientError(
+                    sprintf(_m('That\'s too long. Maximum message size is %d character.', 'That\'s too long. Maximum message size is %d characters.', Message::maxContent()), Message::maxContent()),
+                    406);
+            }
+        }
+
+        if (!$this->other instanceof Profile) {
+            // TRANS: Client error displayed if a recipient user could not be found (403).
+            $this->clientError(_('Recipient user not found.'), 403);
+        } else if (!$this->user->mutuallySubscribed($this->other)) {
+            // TRANS: Client error displayed trying to direct message another user who's not a friend (403).
+            $this->clientError(_('Cannot send direct messages to users who aren\'t your friend.'), 403);
+        } else if ($this->user->id == $this->other->id) {
+
+            // Note: sending msgs to yourself is allowed by Twitter
+
+            // TRANS: Client error displayed trying to direct message self (403).
+            $this->clientError(_('Do not send a message to yourself; just say it to yourself quietly instead.'), 403);
+        }
+
+        $message = Message::saveNew(
+            $this->user->id,
+            $this->other->id,
+            html_entity_decode($this->content, ENT_NOQUOTES, 'UTF-8'),
+            $this->source
+        );
+
+        $message->notify();
+
+        if ($this->format == 'xml') {
+            $this->showSingleXmlDirectMessage($message);
+        } elseif ($this->format == 'json') {
+            $this->showSingleJsondirectMessage($message);
+        }
+    }
+}
diff --git a/plugins/DirectMessage/actions/inbox.php b/plugins/DirectMessage/actions/inbox.php
new file mode 100644 (file)
index 0000000..1a4de6c
--- /dev/null
@@ -0,0 +1,125 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * action handler for message inbox
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Message
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * action handler for message inbox
+ *
+ * @category Message
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ * @see      MailboxAction
+ */
+class InboxAction extends MailboxAction
+{
+
+    /**
+     * Title of the page
+     *
+     * @return string page title
+     */
+    function title()
+    {
+        if ($this->page > 1) {
+            // TRANS: Title for all but the first page of the inbox page.
+            // TRANS: %1$s is the user's nickname, %2$s is the page number.
+            return sprintf(_('Inbox for %1$s - page %2$d'), $this->user->nickname,
+                $this->page);
+        } else {
+            // TRANS: Title for the first page of the inbox page.
+            // TRANS: %s is the user's nickname.
+            return sprintf(_('Inbox for %s'), $this->user->nickname);
+        }
+    }
+
+    /**
+     * Retrieve the messages for this user and this page
+     *
+     * Does a query for the right messages
+     *
+     * @return Message data object with stream for messages
+     *
+     * @see MailboxAction::getMessages()
+     */
+    function getMessages()
+    {
+        $message = new Message();
+
+        $message->to_profile = $this->user->id;
+        $message->orderBy('created DESC, id DESC');
+        $message->limit((($this->page - 1) * MESSAGES_PER_PAGE),
+            MESSAGES_PER_PAGE + 1);
+
+        if ($message->find()) {
+            return $message;
+        } else {
+            return null;
+        }
+    }
+
+    function getMessageList($message)
+    {
+        return new InboxMessageList($this, $message);
+    }
+
+    /**
+     * Instructions for using this page
+     *
+     * @return string localised instructions for using the page
+     */
+    function getInstructions()
+    {
+        // TRANS: Instructions for user inbox page.
+        return _('This is your inbox, which lists your incoming private messages.');
+    }
+}
+
+class InboxMessageList extends MessageList
+{
+    function newItem($message)
+    {
+        return new InboxMessageListItem($this->out, $message);
+    }
+}
+
+class InboxMessageListItem extends MessageListItem
+{
+    /**
+     * Returns the profile we want to show with the message
+     *
+     * @return Profile The profile that matches the message
+     */
+    function getMessageProfile()
+    {
+        return $this->message->getFrom();
+    }
+}
diff --git a/plugins/DirectMessage/actions/newmessage.php b/plugins/DirectMessage/actions/newmessage.php
new file mode 100644 (file)
index 0000000..428a557
--- /dev/null
@@ -0,0 +1,228 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Handler for posting new messages
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Personal
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @author    Zach Copley <zach@status.net>
+ * @author    Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @copyright 2013 Free Software Foundation, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Action for posting new direct messages
+ *
+ * @category Personal
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @author   Zach Copley <zach@status.net>
+ * @author   Sarven Capadisli <csarven@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ */
+
+class NewmessageAction extends FormAction
+{
+    var $content = null;
+    var $to = null;
+    var $other = null;
+
+    /**
+     * Title of the page
+     *
+     * Note that this usually doesn't get called unless something went wrong
+     *
+     * @return string page title
+     */
+
+    function title()
+    {
+        // TRANS: Page title for new direct message page.
+        return _('New message');
+    }
+
+    /**
+     * Handle input, produce output
+     *
+     * @param array $args $_REQUEST contents
+     *
+     * @return void
+     */
+
+    protected function prepare(array $args=array())
+    {
+        parent::prepare($args);
+
+        $this->content = $this->trimmed('content');
+        $this->to = $this->trimmed('to');
+
+        if ($this->to) {
+
+            $this->other = Profile::getKV('id', $this->to);
+
+            if (!$this->other instanceof Profile) {
+                // TRANS: Client error displayed trying to send a direct message to a non-existing user.
+                $this->clientError(_('No such user.'), 404);
+            }
+
+            if (!$this->other->isLocal()) {
+                // TRANS: Explains that current federation does not support direct, private messages yet.
+                $this->clientError(_('You cannot send direct messages to federated users yet.'));
+            }
+
+            if (!$this->scoped->mutuallySubscribed($this->other)) {
+                // TRANS: Client error displayed trying to send a direct message to a user while sender and
+                // TRANS: receiver are not subscribed to each other.
+                $this->clientError(_('You cannot send a message to this user.'), 404);
+            }
+        }
+
+        return true;
+    }
+
+    protected function handlePost()
+    {
+        parent::handlePost();
+
+        assert($this->scoped instanceof Profile); // XXX: maybe an error instead...
+
+        if (!$this->content) {
+            // TRANS: Form validator error displayed trying to send a direct message without content.
+            $this->clientError(_('No content!'));
+        } else {
+            $content_shortened = $this->scoped->shortenLinks($this->content);
+
+            if (Message::contentTooLong($content_shortened)) {
+                // TRANS: Form validation error displayed when message content is too long.
+                // TRANS: %d is the maximum number of characters for a message.
+                $this->clientError(sprintf(_m('That\'s too long. Maximum message size is %d character.',
+                                           'That\'s too long. Maximum message size is %d characters.',
+                                           Message::maxContent()),
+                                        Message::maxContent()));
+            }
+        }
+
+        if (!$this->other) {
+            // TRANS: Form validation error displayed trying to send a direct message without specifying a recipient.
+            $this->clientError(_('No recipient specified.'));
+        } else if (!$this->scoped->mutuallySubscribed($this->other)) {
+            // TRANS: Client error displayed trying to send a direct message to a user while sender and
+            // TRANS: receiver are not subscribed to each other.
+            $this->clientError(_('You cannot send a message to this user.'), 404);
+        } else if ($this->scoped->id == $this->other->id) {
+            // TRANS: Client error displayed trying to send a direct message to self.
+            $this->clientError(_('Do not send a message to yourself; ' .
+                'just say it to yourself quietly instead.'), 403);
+        }
+
+        $message = Message::saveNew($this->scoped->id, $this->other->id, $this->content, 'web');
+        $message->notify();
+
+        if ($this->boolean('ajax')) {
+            $this->startHTML('text/xml;charset=utf-8');
+            $this->elementStart('head');
+            // TRANS: Page title after sending a direct message.
+            $this->element('title', null, _('Message sent'));
+            $this->elementEnd('head');
+            $this->elementStart('body');
+            $this->element('p', array('id' => 'command_result'),
+                // TRANS: Confirmation text after sending a direct message.
+                // TRANS: %s is the direct message recipient.
+                sprintf(_('Direct message to %s sent.'),
+                    $this->other->nickname));
+            $this->elementEnd('body');
+            $this->endHTML();
+        } else {
+            $url = common_local_url('outbox',
+                array('nickname' => $this->scoped->nickname));
+            common_redirect($url, 303);
+        }
+    }
+
+    /**
+     * Show an Ajax-y error message
+     *
+     * Goes back to the browser, where it's shown in a popup.
+     *
+     * @param string $msg Message to show
+     *
+     * @return void
+     */
+
+    function ajaxErrorMsg($msg)
+    {
+        $this->startHTML('text/xml;charset=utf-8', true);
+        $this->elementStart('head');
+        // TRANS: Page title after an AJAX error occurred on the "send direct message" page.
+        $this->element('title', null, _('Ajax Error'));
+        $this->elementEnd('head');
+        $this->elementStart('body');
+        $this->element('p', array('id' => 'error'), $msg);
+        $this->elementEnd('body');
+        $this->endHTML();
+    }
+
+    function showForm($msg = null)
+    {
+        if ($msg && $this->boolean('ajax')) {
+            $this->ajaxErrorMsg($msg);
+            return;
+        }
+
+        $this->msg = $msg;
+        if ($this->trimmed('ajax')) {
+            $this->startHTML('text/xml;charset=utf-8');
+            $this->elementStart('head');
+            // TRANS: Page title on page for sending a direct message.
+            $this->element('title', null, _('New message'));
+            $this->elementEnd('head');
+            $this->elementStart('body');
+            $this->showNoticeForm();
+            $this->elementEnd('body');
+            $this->endHTML();
+        }
+        else {
+            $this->showPage();
+        }
+    }
+
+    function showPageNotice()
+    {
+        if ($this->msg) {
+            $this->element('p', 'error', $this->msg);
+        }
+    }
+
+    // Do nothing (override)
+
+    function showNoticeForm()
+    {
+        $message_form = new MessageForm($this, $this->other, $this->content);
+        $message_form->show();
+    }
+}
diff --git a/plugins/DirectMessage/actions/outbox.php b/plugins/DirectMessage/actions/outbox.php
new file mode 100644 (file)
index 0000000..5b11a1f
--- /dev/null
@@ -0,0 +1,123 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * action handler for message inbox
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Message
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * action handler for message outbox
+ *
+ * @category Message
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ * @see      MailboxAction
+ */
+class OutboxAction extends MailboxAction
+{
+    /**
+     * Title of the page
+     *
+     * @return string page title
+     */
+    function title()
+    {
+        if ($this->page > 1) {
+            // TRANS: Title for outbox for any but the fist page.
+            // TRANS: %1$s is the user nickname, %2$d is the page number.
+            return sprintf(_('Outbox for %1$s - page %2$d'),
+                $this->user->nickname, $page);
+        } else {
+            // TRANS: Title for first page of outbox.
+            return sprintf(_('Outbox for %s'), $this->user->nickname);
+        }
+    }
+
+    /**
+     * retrieve the messages for this user and this page
+     *
+     * Does a query for the right messages
+     *
+     * @return Message data object with stream for messages
+     *
+     * @see MailboxAction::getMessages()
+     */
+    function getMessages()
+    {
+        $message = new Message();
+
+        $message->from_profile = $this->user->id;
+        $message->orderBy('created DESC, id DESC');
+        $message->limit((($this->page - 1) * MESSAGES_PER_PAGE),
+            MESSAGES_PER_PAGE + 1);
+
+        if ($message->find()) {
+            return $message;
+        } else {
+            return null;
+        }
+    }
+
+    function getMessageList($message)
+    {
+        return new OutboxMessageList($this, $message);
+    }
+
+    /**
+     * instructions for using this page
+     *
+     * @return string localised instructions for using the page
+     */
+    function getInstructions()
+    {
+        // TRANS: Instructions for outbox.
+        return _('This is your outbox, which lists private messages you have sent.');
+    }
+}
+
+class OutboxMessageList extends MessageList
+{
+    function newItem($message)
+    {
+        return new OutboxMessageListItem($this->out, $message);
+    }
+}
+
+class OutboxMessageListItem extends MessageListItem
+{
+    /**
+     * Returns the profile we want to show with the message
+     *
+     * @return Profile The profile that matches the message
+     */
+    function getMessageProfile()
+    {
+        return $this->message->getTo();
+    }
+}
diff --git a/plugins/DirectMessage/actions/showmessage.php b/plugins/DirectMessage/actions/showmessage.php
new file mode 100644 (file)
index 0000000..86fbee8
--- /dev/null
@@ -0,0 +1,163 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a single message
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Personal
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+    exit(1);
+}
+
+/**
+ * Show a single message
+ *
+ * @category Personal
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ */
+
+class ShowmessageAction extends Action
+{
+    /**
+     * Message object to show
+     */
+    var $message = null;
+
+    /**
+     * The current user
+     */
+
+    var $user = null;
+
+    /**
+     * Load attributes based on database arguments
+     *
+     * Loads all the DB stuff
+     *
+     * @param array $args $_REQUEST array
+     *
+     * @return success flag
+     */
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $this->page = 1;
+
+        $id            = $this->trimmed('message');
+        $this->message = Message::getKV('id', $id);
+
+        if (!$this->message) {
+            // TRANS: Client error displayed requesting a single message that does not exist.
+            $this->clientError(_('No such message.'), 404);
+        }
+
+        $this->user = common_current_user();
+
+        if (empty($this->user) ||
+            ($this->user->id != $this->message->from_profile &&
+             $this->user->id != $this->message->to_profile)) {
+            // TRANS: Client error displayed requesting a single direct message the requesting user was not a party in.
+            throw new ClientException(_('Only the sender and recipient ' .
+                                        'may read this message.'), 403);
+        }
+
+        return true;
+    }
+
+    function handle($args)
+    {
+        $this->showPage();
+    }
+
+    function title()
+    {
+        if ($this->user->id == $this->message->from_profile) {
+            $to = $this->message->getTo();
+            // @todo FIXME: Might be nice if the timestamp could be localised.
+            // TRANS: Page title for single direct message display when viewing user is the sender.
+            // TRANS: %1$s is the addressed user's nickname, $2$s is a timestamp.
+            return sprintf(_('Message to %1$s on %2$s'),
+                             $to->nickname,
+                             common_exact_date($this->message->created));
+        } else if ($this->user->id == $this->message->to_profile) {
+            $from = $this->message->getFrom();
+            // @todo FIXME: Might be nice if the timestamp could be localised.
+            // TRANS: Page title for single message display.
+            // TRANS: %1$s is the sending user's nickname, $2$s is a timestamp.
+            return sprintf(_('Message from %1$s on %2$s'),
+                             $from->nickname,
+                             common_exact_date($this->message->created));
+        }
+    }
+
+
+    function showContent()
+    {
+        $this->elementStart('ul', 'notices messages');
+        $ml = new ShowMessageListItem($this, $this->message, $this->user);
+        $ml->show();
+        $this->elementEnd('ul');
+    }
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    /**
+     * Don't show aside
+     *
+     * @return void
+     */
+
+    function showAside() {
+    }
+}
+
+class ShowMessageListItem extends MessageListItem
+{
+    var $user;
+
+    function __construct($out, $message, $user)
+    {
+        parent::__construct($out, $message);
+        $this->user = $user;
+    }
+
+    function getMessageProfile()
+    {
+        if ($this->user->id == $this->message->from_profile) {
+            return $this->message->getTo();
+        } else if ($this->user->id == $this->message->to_profile) {
+            return $this->message->getFrom();
+        } else {
+            // This shouldn't happen
+            return null;
+        }
+    }
+}
diff --git a/plugins/DirectMessage/classes/Message.php b/plugins/DirectMessage/classes/Message.php
new file mode 100644 (file)
index 0000000..3818a38
--- /dev/null
@@ -0,0 +1,220 @@
+<?php
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * Table Definition for message
+ */
+
+class Message extends Managed_DataObject
+{
+    ###START_AUTOCODE
+    /* the code below is auto generated do not remove the above tag */
+
+    public $__table = 'message';                         // table name
+    public $id;                              // int(4)  primary_key not_null
+    public $uri;                             // varchar(255)  unique_key
+    public $from_profile;                    // int(4)   not_null
+    public $to_profile;                      // int(4)   not_null
+    public $content;                         // text()
+    public $rendered;                        // text()
+    public $url;                             // varchar(255)
+    public $created;                         // datetime()   not_null
+    public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP
+    public $source;                          // varchar(32)
+
+    /* the code above is auto generated do not remove the tag below */
+    ###END_AUTOCODE
+
+    public static function schemaDef()
+    {
+        return array(
+            'fields' => array(
+                'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
+                'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier'),
+                'from_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is from'),
+                'to_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is to'),
+                'content' => array('type' => 'text', 'description' => 'message content'),
+                'rendered' => array('type' => 'text', 'description' => 'HTML version of the content'),
+                'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
+                'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+                'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+                'source' => array('type' => 'varchar', 'length' => 32, 'description' => 'source of comment, like "web", "im", or "clientname"'),
+            ),
+            'primary key' => array('id'),
+            'unique keys' => array(
+                'message_uri_key' => array('uri'),
+            ),
+            'foreign keys' => array(
+                'message_from_profile_fkey' => array('profile', array('from_profile' => 'id')),
+                'message_to_profile_fkey' => array('profile', array('to_profile' => 'id')),
+            ),
+            'indexes' => array(
+                // @fixme these are really terrible indexes, since you can only sort on one of them at a time.
+                // looks like we really need a (to_profile, created) for inbox and a (from_profile, created) for outbox
+                'message_from_idx' => array('from_profile'),
+                'message_to_idx' => array('to_profile'),
+                'message_created_idx' => array('created'),
+            ),
+        );
+    }
+
+    function getFrom()
+    {
+        return Profile::getKV('id', $this->from_profile);
+    }
+
+    function getTo()
+    {
+        return Profile::getKV('id', $this->to_profile);
+    }
+
+    static function saveNew($from, $to, $content, $source) {
+        $sender = Profile::getKV('id', $from);
+
+        if (!$sender->hasRight(Right::NEWMESSAGE)) {
+            // TRANS: Client exception thrown when a user tries to send a direct message while being banned from sending them.
+            throw new ClientException(_('You are banned from sending direct messages.'));
+        }
+
+        $user = User::getKV('id', $sender->id);
+
+        $msg = new Message();
+
+        $msg->from_profile = $from;
+        $msg->to_profile = $to;
+        if ($user) {
+            // Use the sender's URL shortening options.
+            $msg->content = $user->shortenLinks($content);
+        } else {
+            $msg->content = common_shorten_links($content);
+        }
+        $msg->rendered = common_render_text($msg->content);
+        $msg->created = common_sql_now();
+        $msg->source = $source;
+
+        $result = $msg->insert();
+
+        if (!$result) {
+            common_log_db_error($msg, 'INSERT', __FILE__);
+            // TRANS: Message given when a message could not be stored on the server.
+            throw new ServerException(_('Could not insert message.'));
+        }
+
+        $orig = clone($msg);
+        $msg->uri = common_local_url('showmessage', array('message' => $msg->id));
+
+        $result = $msg->update($orig);
+
+        if (!$result) {
+            common_log_db_error($msg, 'UPDATE', __FILE__);
+            // TRANS: Message given when a message could not be updated on the server.
+            throw new ServerException(_('Could not update message with new URI.'));
+        }
+
+        return $msg;
+    }
+
+    static function maxContent()
+    {
+        $desclimit = common_config('message', 'contentlimit');
+        // null => use global limit (distinct from 0!)
+        if (is_null($desclimit)) {
+            $desclimit = common_config('site', 'textlimit');
+        }
+        return $desclimit;
+    }
+
+    static function contentTooLong($content)
+    {
+        $contentlimit = self::maxContent();
+        return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit));
+    }
+
+    function notify()
+    {
+        $from = User::getKV('id', $this->from_profile);
+        $to   = User::getKV('id', $this->to_profile);
+
+        mail_notify_message($this, $from, $to);
+    }
+
+    function getSource()
+    {
+        if (empty($this->source)) {
+            return false;
+        }
+
+        $ns = new Notice_source();
+        switch ($this->source) {
+        case 'web':
+        case 'xmpp':
+        case 'mail':
+        case 'omb':
+        case 'system':
+        case 'api':
+            $ns->code = $this->source;
+            break;
+        default:
+            $ns = Notice_source::getKV($this->source);
+            if (!$ns instanceof Notice_source) {
+                $ns = new Notice_source();
+                $ns->code = $this->source;
+                $app = Oauth_application::getKV('name', $this->source);
+                if ($app) {
+                    $ns->name = $app->name;
+                    $ns->url  = $app->source_url;
+                }
+            }
+            break;
+        }
+        return $ns;
+    }
+
+    function asActivity()
+    {
+        $act = new Activity();
+
+        if (Event::handle('StartMessageAsActivity', array($this, &$act))) {
+
+            $act->id      = TagURI::mint(sprintf('activity:message:%d', $this->id));
+            $act->time    = strtotime($this->created);
+            $act->link    = $this->url;
+
+            $profile = Profile::getKV('id', $this->from_profile);
+
+            if (empty($profile)) {
+                throw new Exception(sprintf("Sender profile not found: %d", $this->from_profile));
+            }
+            
+            $act->actor            = $profile->asActivityObject();
+            $act->actor->extra[]   = $profile->profileInfo();
+
+            $act->verb = ActivityVerb::POST;
+
+            $act->objects[] = ActivityObject::fromMessage($this);
+
+            $ctx = new ActivityContext();
+
+            $rprofile = Profile::getKV('id', $this->to_profile);
+
+            if (empty($rprofile)) {
+                throw new Exception(sprintf("Receiver profile not found: %d", $this->to_profile));
+            }
+
+            $ctx->attention[$rprofile->getUri()] = ActivityObject::PERSON;
+
+            $act->context = $ctx;
+
+            $source = $this->getSource();
+
+            if ($source instanceof Notice_source) {
+                $act->generator = ActivityObject::fromNoticeSource($source);
+            }
+
+            Event::handle('EndMessageAsActivity', array($this, &$act));
+        }
+
+        return $act;
+    }
+}
diff --git a/plugins/DirectMessage/lib/inboxmessagelist.php b/plugins/DirectMessage/lib/inboxmessagelist.php
new file mode 100644 (file)
index 0000000..3c7281e
--- /dev/null
@@ -0,0 +1,167 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * common superclass for direct messages inbox and outbox
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Message
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+    exit(1);
+}
+
+/**
+ * common superclass for direct messages inbox and outbox
+ *
+ * @category Message
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ * @see      InboxAction
+ * @see      OutboxAction
+ */
+class MailboxAction extends Action
+{
+    var $page = null;
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $nickname   = common_canonical_nickname($this->arg('nickname'));
+        $this->user = User::getKV('nickname', $nickname);
+        $this->page = $this->trimmed('page');
+
+        if (!$this->page) {
+            $this->page = 1;
+        }
+
+        common_set_returnto($this->selfUrl());
+
+        return true;
+    }
+
+    /**
+     * output page based on arguments
+     *
+     * @param array $args HTTP arguments (from $_REQUEST)
+     *
+     * @return void
+     */
+    function handle($args)
+    {
+        parent::handle($args);
+
+        if (!$this->user) {
+            // TRANS: Client error displayed when trying to access a mailbox without providing a user.
+            $this->clientError(_('No such user.'), 404);
+        }
+
+        $cur = common_current_user();
+
+        if (!$cur || $cur->id != $this->user->id) {
+            // TRANS: Client error displayed when trying to access a mailbox that is not of the logged in user.
+            $this->clientError(_('Only the user can read their own mailboxes.'), 403);
+        }
+
+        $this->showPage();
+    }
+
+    function showNoticeForm()
+    {
+        $message_form = new MessageForm($this);
+        $message_form->show();
+    }
+
+    function showContent()
+    {
+        $message = $this->getMessages();
+
+        if ($message) {
+
+            $ml = $this->getMessageList($message);
+
+            $cnt = $ml->show();
+
+            $this->pagination($this->page > 1,
+                              $cnt > MESSAGES_PER_PAGE,
+                              $this->page,
+                              $this->trimmed('action'),
+                              array('nickname' => $this->user->nickname));
+        } else {
+            $this->element('p',
+                           'guide',
+                           // TRANS: Message displayed when there are no private messages in the inbox of a user.
+                           _('You have no private messages. '.
+                             'You can send private message to engage other users in conversation. '.
+                             'People can send you messages for your eyes only.'));
+        }
+    }
+
+    function getMessages()
+    {
+        return null;
+    }
+
+    function getMessageList($message)
+    {
+        return null;
+    }
+
+    /**
+     * Show the page notice
+     *
+     * Shows instructions for the page
+     *
+     * @return void
+     */
+    function showPageNotice()
+    {
+        $instr  = $this->getInstructions();
+        $output = common_markup_to_html($instr);
+
+        $this->elementStart('div', 'instructions');
+        $this->raw($output);
+        $this->elementEnd('div');
+    }
+
+    /**
+     * Mailbox actions are read only
+     *
+     * @param array $args other arguments
+     *
+     * @return boolean
+     */
+    function isReadOnly($args)
+    {
+         return true;
+    }
+
+    function showObjectNav()
+    {
+        $mm = new MailboxMenu($this);
+        $mm->show();
+    }
+}
diff --git a/plugins/DirectMessage/lib/mailboxaction.php b/plugins/DirectMessage/lib/mailboxaction.php
new file mode 100644 (file)
index 0000000..3c7281e
--- /dev/null
@@ -0,0 +1,167 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * common superclass for direct messages inbox and outbox
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Message
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+    exit(1);
+}
+
+/**
+ * common superclass for direct messages inbox and outbox
+ *
+ * @category Message
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ * @see      InboxAction
+ * @see      OutboxAction
+ */
+class MailboxAction extends Action
+{
+    var $page = null;
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+
+        $nickname   = common_canonical_nickname($this->arg('nickname'));
+        $this->user = User::getKV('nickname', $nickname);
+        $this->page = $this->trimmed('page');
+
+        if (!$this->page) {
+            $this->page = 1;
+        }
+
+        common_set_returnto($this->selfUrl());
+
+        return true;
+    }
+
+    /**
+     * output page based on arguments
+     *
+     * @param array $args HTTP arguments (from $_REQUEST)
+     *
+     * @return void
+     */
+    function handle($args)
+    {
+        parent::handle($args);
+
+        if (!$this->user) {
+            // TRANS: Client error displayed when trying to access a mailbox without providing a user.
+            $this->clientError(_('No such user.'), 404);
+        }
+
+        $cur = common_current_user();
+
+        if (!$cur || $cur->id != $this->user->id) {
+            // TRANS: Client error displayed when trying to access a mailbox that is not of the logged in user.
+            $this->clientError(_('Only the user can read their own mailboxes.'), 403);
+        }
+
+        $this->showPage();
+    }
+
+    function showNoticeForm()
+    {
+        $message_form = new MessageForm($this);
+        $message_form->show();
+    }
+
+    function showContent()
+    {
+        $message = $this->getMessages();
+
+        if ($message) {
+
+            $ml = $this->getMessageList($message);
+
+            $cnt = $ml->show();
+
+            $this->pagination($this->page > 1,
+                              $cnt > MESSAGES_PER_PAGE,
+                              $this->page,
+                              $this->trimmed('action'),
+                              array('nickname' => $this->user->nickname));
+        } else {
+            $this->element('p',
+                           'guide',
+                           // TRANS: Message displayed when there are no private messages in the inbox of a user.
+                           _('You have no private messages. '.
+                             'You can send private message to engage other users in conversation. '.
+                             'People can send you messages for your eyes only.'));
+        }
+    }
+
+    function getMessages()
+    {
+        return null;
+    }
+
+    function getMessageList($message)
+    {
+        return null;
+    }
+
+    /**
+     * Show the page notice
+     *
+     * Shows instructions for the page
+     *
+     * @return void
+     */
+    function showPageNotice()
+    {
+        $instr  = $this->getInstructions();
+        $output = common_markup_to_html($instr);
+
+        $this->elementStart('div', 'instructions');
+        $this->raw($output);
+        $this->elementEnd('div');
+    }
+
+    /**
+     * Mailbox actions are read only
+     *
+     * @param array $args other arguments
+     *
+     * @return boolean
+     */
+    function isReadOnly($args)
+    {
+         return true;
+    }
+
+    function showObjectNav()
+    {
+        $mm = new MailboxMenu($this);
+        $mm->show();
+    }
+}
diff --git a/plugins/DirectMessage/lib/mailboxmenu.php b/plugins/DirectMessage/lib/mailboxmenu.php
new file mode 100644 (file)
index 0000000..49e7dce
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Private mailboxes menu
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Cache
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    // This check helps protect against security problems;
+    // your code file can't be executed directly from the web.
+    exit(1);
+}
+
+/**
+ * Menu of existing mailboxes
+ *
+ * @category  General
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+class MailboxMenu extends Menu
+{
+    function show()
+    {
+        $cur = common_current_user();
+        $nickname = $cur->nickname;
+
+        $this->out->elementStart('ul', array('class' => 'nav'));
+
+        $this->item('inbox',
+                    array('nickname' => $nickname),
+                    // TRANS: Menu item in mailbox menu. Leads to incoming private messages.
+                    _m('MENU','Inbox'),
+                    // TRANS: Menu item title in mailbox menu. Leads to incoming private messages.
+                    _('Your incoming messages.'));
+
+        $this->item('outbox',
+                    array('nickname' => $nickname),
+                    // TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
+                    _m('MENU','Outbox'),
+                    // TRANS: Menu item title in mailbox menu. Leads to outgoing private messages.
+                    _('Your sent messages.'));
+
+        $this->out->elementEnd('ul');
+    }
+}
diff --git a/plugins/DirectMessage/lib/messagecommand.php b/plugins/DirectMessage/lib/messagecommand.php
new file mode 100644 (file)
index 0000000..5912e3d
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+
+class MessageCommand extends Command
+{
+    var $other = null;
+    var $text = null;
+    function __construct($user, $other, $text)
+    {
+        parent::__construct($user);
+        $this->other = $other;
+        $this->text = $text;
+    }
+
+    function handle($channel)
+    {
+        try {
+            $other = $this->getUser($this->other)->getProfile();
+        } catch (CommandException $e) {
+            try {
+                $profile = $this->getProfile($this->other);
+            } catch (CommandException $f) {
+                throw $e;
+            }
+            // TRANS: Command exception text shown when trying to send a direct message to a remote user (a user not registered at the current server).
+            // TRANS: %s is a remote profile.
+            throw new CommandException(sprintf(_('%s is a remote profile; you can only send direct messages to users on the same server.'), $this->other));
+        }
+
+        $len = mb_strlen($this->text);
+
+        if ($len == 0) {
+            // TRANS: Command exception text shown when trying to send a direct message to another user without content.
+            $channel->error($this->user, _('No content!'));
+            return;
+        }
+
+        $this->text = $this->user->shortenLinks($this->text);
+
+        if (Message::contentTooLong($this->text)) {
+            // XXX: i18n. Needs plural support.
+            // TRANS: Message given if content is too long. %1$sd is used for plural.
+            // TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters.
+            $channel->error($this->user, sprintf(_m('Message too long - maximum is %1$d character, you sent %2$d.',
+                                                    'Message too long - maximum is %1$d characters, you sent %2$d.',
+                                                    Message::maxContent()),
+                                                 Message::maxContent(), mb_strlen($this->text)));
+            return;
+        }
+
+        if (!$other instanceof Profile) {
+            // TRANS: Error text shown when trying to send a direct message to a user that does not exist.
+            $channel->error($this->user, _('No such user.'));
+            return;
+        } else if (!$this->user->mutuallySubscribed($other)) {
+            // TRANS: Error text shown when trying to send a direct message to a user without a mutual subscription (each user must be subscribed to the other).
+            $channel->error($this->user, _('You can\'t send a message to this user.'));
+            return;
+        } else if ($this->user->id == $other->id) {
+            // TRANS: Error text shown when trying to send a direct message to self.
+            $channel->error($this->user, _('Do not send a message to yourself; just say it to yourself quietly instead.'));
+            return;
+        }
+        try {
+            $message = Message::saveNew($this->user->id, $other->id, $this->text, $channel->source());
+            $message->notify();
+            // TRANS: Message given have sent a direct message to another user.
+            // TRANS: %s is the name of the other user.
+            $channel->output($this->user, sprintf(_('Direct message to %s sent.'), $this->other));
+        } catch (Exception $e) {
+            // TRANS: Error text shown sending a direct message fails with an unknown reason.
+            $channel->error($this->user, $e->getMessage());
+        }
+    }
+}
diff --git a/plugins/DirectMessage/lib/messageform.php b/plugins/DirectMessage/lib/messageform.php
new file mode 100644 (file)
index 0000000..96059e4
--- /dev/null
@@ -0,0 +1,205 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for posting a direct message
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Form
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @author    Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * Form for posting a direct message
+ *
+ * @category Form
+ * @package  StatusNet
+ * @author   Evan Prodromou <evan@status.net>
+ * @author   Sarven Capadisli <csarven@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ * @see      HTMLOutputter
+ */
+class MessageForm extends Form
+{
+    /**
+     * User to send a direct message to
+     */
+    var $to = null;
+
+    /**
+     * Pre-filled content of the form
+     */
+    var $content = null;
+
+    /**
+     * Constructor
+     *
+     * @param HTMLOutputter $out     output channel
+     * @param User          $to      user to send a message to
+     * @param string        $content content to pre-fill
+     */
+    function __construct($out=null, $to=null, $content=null)
+    {
+        parent::__construct($out);
+
+        $this->to      = $to;
+        $this->content = $content;
+    }
+
+    /**
+     * ID of the form
+     *
+     * @return string ID of the form
+     */
+    function id()
+    {
+        return 'form_notice-direct';
+    }
+
+   /**
+     * Class of the form
+     *
+     * @return string class of the form
+     */
+    function formClass()
+    {
+        return 'form_notice ajax-notice';
+    }
+
+    /**
+     * Action of the form
+     *
+     * @return string URL of the action
+     */
+    function action()
+    {
+        return common_local_url('newmessage');
+    }
+
+    /**
+     * Legend of the Form
+     *
+     * @return void
+     */
+    function formLegend()
+    {
+        // TRANS: Form legend for direct notice.
+        $this->out->element('legend', null, _('Send a direct notice'));
+    }
+
+    /**
+     * Data elements
+     *
+     * @return void
+     */
+    function formData()
+    {
+        $user = common_current_user();
+
+        $mutual_users = $user->mutuallySubscribedUsers();
+
+        $mutual = array();
+        // TRANS: Label entry in drop-down selection box in direct-message inbox/outbox.
+        // TRANS: This is the default entry in the drop-down box, doubling as instructions
+        // TRANS: and a brake against accidental submissions with the first user in the list.
+        $mutual[0] = _('Select recipient:');
+
+        while ($mutual_users->fetch()) {
+            if ($mutual_users->id != $user->id) {
+                $mutual[$mutual_users->id] = $mutual_users->nickname;
+            }
+        }
+
+        $mutual_users->free();
+        unset($mutual_users);
+
+        if (count($mutual) == 1) {
+            // TRANS: Entry in drop-down selection box in direct-message inbox/outbox when no one is available to message.
+            $mutual[0] = _('No mutual subscribers.');
+        }
+
+        // TRANS: Dropdown label in direct notice form.
+        $this->out->dropdown('to', _('To'), $mutual, null, false,
+                             ($this->to) ? $this->to->id : null);
+
+        $this->out->element('textarea', array('class' => 'notice_data-text',
+                                              'cols' => 35,
+                                              'rows' => 4,
+                                              'name' => 'content'),
+                            ($this->content) ? $this->content : '');
+
+        $contentLimit = Message::maxContent();
+
+        if ($contentLimit > 0) {
+            $this->out->element('span',
+                                array('class' => 'count'),
+                                $contentLimit);
+        }
+    }
+
+    /**
+     * Action elements
+     *
+     * @return void
+     */
+    function formActions()
+    {
+        $this->out->element('input', array('id' => 'notice_action-submit',
+                                           'class' => 'submit',
+                                           'name' => 'message_send',
+                                           'type' => 'submit',
+                                           // TRANS: Button text for sending a direct notice.
+                                           'value' => _m('Send button for sending notice', 'Send')));
+    }
+
+
+    /**
+     * Show the form
+     *
+     * Uses a recipe to output the form.
+     *
+     * @return void
+     * @see Widget::show()
+     */
+
+    function show()
+    {
+        $this->elementStart('div', 'input_forms');
+        $this->elementStart(
+            'div',
+            array(
+                'id'    => 'input_form_direct',
+                'class' => 'input_form current nonav'
+            )
+        );
+
+        parent::show();
+
+        $this->elementEnd('div');
+        $this->elementEnd('div');
+
+    }
+}
diff --git a/plugins/DirectMessage/lib/messagelist.php b/plugins/DirectMessage/lib/messagelist.php
new file mode 100644 (file)
index 0000000..0185977
--- /dev/null
@@ -0,0 +1,107 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * The message list widget
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Widget
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    // This check helps protect against security problems;
+    // your code file can't be executed directly from the web.
+    exit(1);
+}
+
+/**
+ * Message list widget
+ *
+ * @category  Widget
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+abstract class MessageList extends Widget
+{
+    var $message;
+
+    /**
+     * Constructor
+     *
+     * @param HTMLOutputter $out     Output context
+     * @param Message       $message Stream of messages to show
+     */
+    function __construct($out, $message)
+    {
+        parent::__construct($out);
+        $this->message = $message;
+    }
+
+    /**
+     * Show the widget
+     *
+     * Uses newItem() to create each new item.
+     *
+     * @return integer count of messages seen.
+     */
+    function show()
+    {
+            $cnt = 0;
+
+            $this->out->elementStart('div', array('id' =>'notices_primary'));
+
+            // TRANS: Header in message list.
+            $this->out->element('h2', null, _('Messages'));
+
+            $this->out->elementStart('ul', 'notices messages');
+
+            while ($this->message->fetch() && $cnt <= MESSAGES_PER_PAGE) {
+
+                $cnt++;
+
+                if ($cnt > MESSAGES_PER_PAGE) {
+                    break;
+                }
+
+                $mli = $this->newItem($this->message);
+
+                $mli->show();
+            }
+
+            $this->out->elementEnd('ul');
+
+            $this->out->elementEnd('div');
+    }
+
+    /**
+     * Create a new message item for a message
+     *
+     * @param Message $message The message to show
+     *
+     * @return MessageListItem an item to show
+     */
+    abstract function newItem($message);
+}
diff --git a/plugins/DirectMessage/lib/messagelistitem.php b/plugins/DirectMessage/lib/messagelistitem.php
new file mode 100644 (file)
index 0000000..c9f4c60
--- /dev/null
@@ -0,0 +1,194 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * A single list item for showing in a message list
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Widget
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    // This check helps protect against security problems;
+    // your code file can't be executed directly from the web.
+    exit(1);
+}
+
+/**
+ * A single item in a message list
+ *
+ * @category  Widget
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+abstract class MessageListItem extends Widget
+{
+    var $message;
+
+    /**
+     * Constructor
+     *
+     * @param HTMLOutputter $out     Output context
+     * @param Message       $message Message to show
+     */
+    function __construct($out, $message)
+    {
+        parent::__construct($out);
+        $this->message = $message;
+    }
+
+    /**
+     * Show the widget
+     *
+     * @return void
+     */
+    function show()
+    {
+        $this->out->elementStart('li', array('class' => 'h-entry notice',
+                                             'id' => 'message-' . $this->message->id));
+
+        $profile = $this->getMessageProfile();
+
+        $this->out->elementStart('a', array('href' => $profile->profileurl,
+                                            'class' => 'p-author'));
+        $avatarUrl = $profile->avatarUrl(AVATAR_STREAM_SIZE);
+        $this->out->element('img', array('src' => $avatarUrl,
+                                         'class' => 'avatar u-photo',
+                                         'width' => AVATAR_STREAM_SIZE,
+                                         'height' => AVATAR_STREAM_SIZE,
+                                         'alt' => $profile->getBestName()));
+        $this->out->element('span', array('class' => 'nickname fn'), $profile->getNickname());
+        $this->out->elementEnd('a');
+
+        // FIXME: URL, image, video, audio
+        $this->out->elementStart('div', array('class' => 'e-content'));
+        $this->out->raw($this->message->rendered);
+        $this->out->elementEnd('div');
+
+        $messageurl = common_local_url('showmessage',
+                                       array('message' => $this->message->id));
+
+        // XXX: we need to figure this out better. Is this right?
+        if (strcmp($this->message->uri, $messageurl) != 0 &&
+            preg_match('/^http/', $this->message->uri)) {
+            $messageurl = $this->message->uri;
+        }
+
+        $this->out->elementStart('div', 'entry-metadata');
+        $this->out->elementStart('a', array('rel' => 'bookmark',
+                                            'class' => 'timestamp',
+                                            'href' => $messageurl));
+        $dt = common_date_iso8601($this->message->created);
+        $this->out->element('time', array('class' => 'dt-published',
+                                          'datetime' => common_date_iso8601($this->message->created),
+                                          // TRANS: Timestamp title (tooltip text) for NoticeListItem
+                                          'title' => common_exact_date($this->message->created)),
+                            common_date_string($this->message->created));
+        $this->out->elementEnd('a');
+
+        if ($this->message->source) {
+            $this->out->elementStart('span', 'source');
+            // FIXME: bad i18n. Device should be a parameter (from %s).
+            // TRANS: Followed by notice source (usually the client used to send the notice).
+            $this->out->text(_('from'));
+            $this->showSource($this->message->source);
+            $this->out->elementEnd('span');
+        }
+        $this->out->elementEnd('div');
+
+        $this->out->elementEnd('li');
+    }
+
+    /**
+     * Dummy method. Serves no other purpose than to make strings available used
+     * in self::showSource() through xgettext.
+     *
+     * @return void
+     */
+    function messageListItemDummyMessages()
+    {
+        // A dummy array with messages. These will get extracted by xgettext and
+        // are used in self::showSource().
+        $dummy_messages = array(
+            // TRANS: A possible notice source (web interface).
+            _m('SOURCE','web'),
+            // TRANS: A possible notice source (XMPP).
+            _m('SOURCE','xmpp'),
+            // TRANS: A possible notice source (e-mail).
+            _m('SOURCE','mail'),
+            // TRANS: A possible notice source (OpenMicroBlogging).
+            _m('SOURCE','omb'),
+            // TRANS: A possible notice source (Application Programming Interface).
+            _m('SOURCE','api'),
+        );
+    }
+
+    /**
+     * Show the source of the message
+     *
+     * Returns either the name (and link) of the API client that posted the notice,
+     * or one of other other channels.
+     *
+     * @param string $source the source of the message
+     *
+     * @return void
+     */
+    function showSource($source)
+    {
+        $source_name = _m('SOURCE',$source);
+        switch ($source) {
+        case 'web':
+        case 'xmpp':
+        case 'mail':
+        case 'omb':
+        case 'api':
+            $this->out->element('span', 'device', $source_name);
+            break;
+        default:
+            $ns = Notice_source::getKV($source);
+            if ($ns) {
+                $this->out->elementStart('span', 'device');
+                $this->out->element('a', array('href' => $ns->url,
+                                               'rel' => 'external'),
+                                    $ns->name);
+                $this->out->elementEnd('span');
+            } else {
+                $this->out->element('span', 'device', $source_name);
+            }
+            break;
+        }
+        return;
+    }
+
+    /**
+     * Return the profile to show in the message item
+     *
+     * Overridden in sub-classes to show sender, receiver, or whatever
+     *
+     * @return Profile profile to show avatar and name of
+     */
+    abstract function getMessageProfile();
+}
index caf137c29ec6ad0d171248d5a457d5caa9b1f45e..7ac0f9326588684d1dc61b9d383f7db513f7251c 100644 (file)
@@ -71,12 +71,12 @@ class DirectoryPlugin extends Plugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing,
      *         false means stop.
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
 
         $m->connect(
index 2849e75eba6fb69c5e8fc8f84dac17218d966d1c..7474d0daa608f9cfa9a037a8da1b4f71bf11e13a 100644 (file)
@@ -221,6 +221,23 @@ class SortableGroupListItem extends SortableSubscriptionListItem
         $this->endProfile();
     }
 
+    function endActions()
+    {
+        // delete button
+        $cur = common_current_user();
+        list($action, $r2args) = $this->out->returnToArgs();
+        $r2args['action'] = $action;
+        if ($cur instanceof User && $cur->hasRight(Right::DELETEGROUP)) {
+            $this->out->elementStart('li', 'entity_delete');
+            $df = new DeleteGroupForm($this->out, $this->profile, $r2args);
+            $df->show();
+            $this->out->elementEnd('li');
+        }
+
+        $this->out->elementEnd('ul');
+        $this->out->elementEnd('td');
+    }
+
     function showActions()
     {
         $this->startActions();
index bfc9c91606ec373519a1fdcfb10b83613c7af0ec..8d661bbd8525d62e49a2217dfaacb4c92225e561 100644 (file)
@@ -67,11 +67,11 @@ class EventPlugin extends MicroAppPlugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('main/event/new',
                     array('action' => 'newevent'));
@@ -254,24 +254,6 @@ class EventPlugin extends MicroAppPlugin
         return true;
     }
 
-    function adaptNoticeListItem($nli)
-    {
-        $notice = $nli->notice;
-
-        switch ($notice->object_type) {
-        case Happening::OBJECT_TYPE:
-            return new EventListItem($nli);
-            break;
-        case RSVP::POSITIVE:
-        case RSVP::NEGATIVE:
-        case RSVP::POSSIBLE:
-            return new RSVPListItem($nli);
-            break;
-        }
-        return null;
-    }
-
-
     /**
      * Form for our app
      *
@@ -329,4 +311,172 @@ class EventPlugin extends MicroAppPlugin
         }
         return true;
     }
+
+    protected function showNoticeItemNotice(NoticeListItem $nli)
+    {
+        $nli->showAuthor();
+        $nli->showContent();
+    }
+
+    protected function showNoticeContent(Notice $stored, HTMLOutputter $out, Profile $scoped=null)
+    {
+        switch ($stored->object_type) {
+        case Happening::OBJECT_TYPE:
+            $this->showEvent($stored, $out, $scoped);
+            break;
+        case RSVP::POSITIVE:
+        case RSVP::NEGATIVE:
+        case RSVP::POSSIBLE:
+            $this->showRSVP($stored, $out, $scoped);
+            break;
+        }
+    }
+
+    protected function showEvent(Notice $stored, HTMLOutputter $out, Profile $scoped=null)
+    {
+        $profile = $stored->getProfile();
+        $event   = Happening::fromNotice($stored);
+
+        if (!$event instanceof Happening) {
+            // TRANS: Content for a deleted RSVP list item (RSVP stands for "please respond").
+            $out->element('p', null, _m('Deleted.'));
+            return;
+        }
+
+        $out->elementStart('div', 'h-event');
+
+        $out->elementStart('h3', 'p-summary p-name');
+
+        try {
+            $out->element('a', array('href' => $event->getUrl()), $event->title);
+        } catch (InvalidUrlException $e) {
+            $out->text($event->title);
+        }
+
+        $out->elementEnd('h3');
+
+        $now       = new DateTime();
+        $startDate = new DateTime($event->start_time);
+        $endDate   = new DateTime($event->end_time);
+        $userTz    = new DateTimeZone(common_timezone());
+
+        // Localize the time for the observer
+        $now->setTimeZone($userTz);
+        $startDate->setTimezone($userTz);
+        $endDate->setTimezone($userTz);
+
+        $thisYear  = $now->format('Y');
+        $startYear = $startDate->format('Y');
+        $endYear   = $endDate->format('Y');
+
+        $dateFmt = 'D, F j, '; // e.g.: Mon, Aug 31
+
+        if ($startYear != $thisYear || $endYear != $thisYear) {
+            $dateFmt .= 'Y,'; // append year if we need to think about years
+        }
+
+        $startDateStr = $startDate->format($dateFmt);
+        $endDateStr = $endDate->format($dateFmt);
+
+        $timeFmt = 'g:ia';
+
+        $startTimeStr = $startDate->format($timeFmt);
+        $endTimeStr = $endDate->format("{$timeFmt} (T)");
+
+        $out->elementStart('div', 'event-times'); // VEVENT/EVENT-TIMES IN
+
+        // TRANS: Field label for event description.
+        $out->element('strong', null, _m('Time:'));
+
+        $out->element('time', array('class' => 'dt-start',
+                                    'datetime' => common_date_iso8601($event->start_time)),
+                      $startDateStr . ' ' . $startTimeStr);
+        $out->text(' â€“ ');
+        $out->element('time', array('class' => 'dt-end',
+                                    'datetime' => common_date_iso8601($event->end_time)),
+                      $startDateStr != $endDateStr
+                                    ? "$endDateStr $endTimeStr"
+                                    :  $endTimeStr);
+
+        $out->elementEnd('div'); // VEVENT/EVENT-TIMES OUT
+
+        if (!empty($event->location)) {
+            $out->elementStart('div', 'event-location');
+            // TRANS: Field label for event description.
+            $out->element('strong', null, _m('Location:'));
+            $out->element('span', 'p-location', $event->location);
+            $out->elementEnd('div');
+        }
+
+        if (!empty($event->description)) {
+            $out->elementStart('div', 'event-description');
+            // TRANS: Field label for event description.
+            $out->element('strong', null, _m('Description:'));
+            $out->element('div', 'p-description', $event->description);
+            $out->elementEnd('div');
+        }
+
+        $rsvps = $event->getRSVPs();
+
+        $out->elementStart('div', 'event-rsvps');
+
+        // TRANS: Field label for event description.
+        $out->element('strong', null, _m('Attending:'));
+        $out->elementStart('ul', 'attending-list');
+
+        foreach ($rsvps as $verb => $responses) {
+            $out->elementStart('li', 'rsvp-list');
+            switch ($verb) {
+            case RSVP::POSITIVE:
+                $out->text(_('Yes:'));
+                break;
+            case RSVP::NEGATIVE:
+                $out->text(_('No:'));
+                break;
+            case RSVP::POSSIBLE:
+                $out->text(_('Maybe:'));
+                break;
+            }
+            $ids = array();
+            foreach ($responses as $response) {
+                $ids[] = $response->profile_id;
+            }
+            $ids = array_slice($ids, 0, ProfileMiniList::MAX_PROFILES + 1);
+            $minilist = new ProfileMiniList(Profile::multiGet('id', $ids), $out);
+            $minilist->show();
+
+            $out->elementEnd('li');
+        }
+
+        $out->elementEnd('ul');
+        $out->elementEnd('div');
+
+        if ($scoped instanceof Profile) {
+            $rsvp = $event->getRSVP($scoped);
+
+            if (empty($rsvp)) {
+                $form = new RSVPForm($event, $out);
+            } else {
+                $form = new CancelRSVPForm($rsvp, $out);
+            }
+
+            $form->show();
+        }
+        $out->elementEnd('div');
+    }
+
+    protected function showRSVP(Notice $stored, HTMLOutputter $out, Profile $scoped=null)
+    {
+        $rsvp = RSVP::fromNotice($stored);
+
+        if (empty($rsvp)) {
+            // TRANS: Content for a deleted RSVP list item (RSVP stands for "please respond").
+            $out->element('p', null, _m('Deleted.'));
+            return;
+        }
+
+        $out->elementStart('div', 'rsvp');
+        $out->raw($rsvp->asHTML());
+        $out->elementEnd('div');
+    }
 }
index de3307fad4e4352ef6ca1c4bc3cfbc967e6e00e0..7266ea7493aa0ba7a508a8a78ca0e358750aefb0 100644 (file)
@@ -342,7 +342,6 @@ class RSVP extends Managed_DataObject
             // TRANS: Exception thrown when requesting a user's RSVP status for a non-existing response code.
             // TRANS: %s is the non-existing response code.
             throw new Exception(sprintf(_m('Unknown response code %s.'),$response));
-            break;
         }
 
         if (empty($event)) {
diff --git a/plugins/Event/lib/eventlistitem.php b/plugins/Event/lib/eventlistitem.php
deleted file mode 100644 (file)
index 9ad5ee2..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Notice-list representation of an event
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Event
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * Notice-list representation of an event
- *
- * @category  General
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-class EventListItem extends NoticeListItemAdapter
-{
-    function showNotice()
-    {
-        $this->nli->showAuthor();
-        $this->showContent();
-    }
-
-    function showContent()
-    {
-        $notice = $this->nli->notice;
-        $out    = $this->nli->out;
-
-        $profile = $notice->getProfile();
-        $event   = Happening::fromNotice($notice);
-
-        if (empty($event)) {
-            // TRANS: Content for a deleted RSVP list item (RSVP stands for "please respond").
-            $out->element('p', null, _m('Deleted.'));
-            return;
-        }
-
-        // e-content since we're part of a h-entry
-        $out->elementStart('div', 'h-event e-content'); // VEVENT IN
-
-        $out->elementStart('h3', 'p-summary p-name');  // VEVENT/H3 IN
-
-        try {
-            $out->element('a', array('href' => $event->getUrl()), $event->title);
-        } catch (InvalidUrlException $e) {
-            $out->text($event->title);
-        }
-
-        $out->elementEnd('h3'); // VEVENT/H3 OUT
-
-        $now       = new DateTime();
-        $startDate = new DateTime($event->start_time);
-        $endDate   = new DateTime($event->end_time);
-        $userTz    = new DateTimeZone(common_timezone());
-
-        // Localize the time for the observer
-        $now->setTimeZone($userTz);
-        $startDate->setTimezone($userTz);
-        $endDate->setTimezone($userTz);
-
-        $thisYear  = $now->format('Y');
-        $startYear = $startDate->format('Y');
-        $endYear   = $endDate->format('Y');
-
-        $dateFmt = 'D, F j, '; // e.g.: Mon, Aug 31
-
-        if ($startYear != $thisYear || $endYear != $thisYear) {
-            $dateFmt .= 'Y,'; // append year if we need to think about years
-        }
-
-        $startDateStr = $startDate->format($dateFmt);
-        $endDateStr = $endDate->format($dateFmt);
-
-        $timeFmt = 'g:ia';
-
-        $startTimeStr = $startDate->format($timeFmt);
-        $endTimeStr = $endDate->format("{$timeFmt} (T)");
-
-        $out->elementStart('div', 'event-times'); // VEVENT/EVENT-TIMES IN
-
-        // TRANS: Field label for event description.
-        $out->element('strong', null, _m('Time:'));
-
-        $out->element('time', array('class' => 'dt-start',
-                                    'datetime' => common_date_iso8601($event->start_time)),
-                      $startDateStr . ' ' . $startTimeStr);
-        $out->text(' â€“ ');
-        $out->element('time', array('class' => 'dt-end',
-                                    'datetime' => common_date_iso8601($event->end_time)),
-                      $startDateStr != $endDateStr
-                                    ? "$endDateStr $endTimeStr"
-                                    :  $endTimeStr);
-
-        $out->elementEnd('div'); // VEVENT/EVENT-TIMES OUT
-
-        if (!empty($event->location)) {
-            $out->elementStart('div', 'event-location');
-            // TRANS: Field label for event description.
-            $out->element('strong', null, _m('Location:'));
-            $out->element('span', 'p-location', $event->location);
-            $out->elementEnd('div');
-        }
-
-        if (!empty($event->description)) {
-            $out->elementStart('div', 'event-description');
-            // TRANS: Field label for event description.
-            $out->element('strong', null, _m('Description:'));
-            $out->element('div', 'p-description', $event->description);
-            $out->elementEnd('div');
-        }
-
-        $rsvps = $event->getRSVPs();
-
-        $out->elementStart('div', 'event-rsvps');
-
-        // TRANS: Field label for event description.
-        $out->element('strong', null, _m('Attending:'));
-        $out->elementStart('ul', 'attending-list');
-
-        foreach ($rsvps as $verb => $responses) {
-            $out->elementStart('li', 'rsvp-list');
-            switch ($verb) {
-            case RSVP::POSITIVE:
-                $out->text(_('Yes:'));
-                break;
-            case RSVP::NEGATIVE:
-                $out->text(_('No:'));
-                break;
-            case RSVP::POSSIBLE:
-                $out->text(_('Maybe:'));
-                break;
-            }
-            $ids = array();
-            foreach ($responses as $response) {
-                $ids[] = $response->profile_id;
-            }
-            $ids = array_slice($ids, 0, ProfileMiniList::MAX_PROFILES + 1);
-            $minilist = new ProfileMiniList(Profile::multiGet('id', $ids), $out);
-            $minilist->show();
-
-            $out->elementEnd('li');
-        }
-
-        $out->elementEnd('ul');
-        $out->elementEnd('div');
-
-        $user = common_current_user();
-
-        if (!empty($user)) {
-            $rsvp = $event->getRSVP($user->getProfile());
-
-            if (empty($rsvp)) {
-                $form = new RSVPForm($event, $out);
-            } else {
-                $form = new CancelRSVPForm($rsvp, $out);
-            }
-
-            $form->show();
-        }
-
-        $out->elementEnd('div'); // vevent out
-    }
-}
diff --git a/plugins/Event/lib/rsvplistitem.php b/plugins/Event/lib/rsvplistitem.php
deleted file mode 100644 (file)
index fef1c9d..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Title of module
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Cache
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * Class comment
- *
- * @category  General
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-class RSVPListItem extends NoticeListItemAdapter
-{
-    function showNotice()
-    {
-        $this->nli->out->elementStart('div', 'entry-title');
-        $this->nli->showAuthor();
-        $this->showContent();
-        $this->nli->out->elementEnd('div');
-    }
-
-    function showContent()
-    {
-        $notice = $this->nli->notice;
-        $out    = $this->nli->out;
-
-        $rsvp = RSVP::fromNotice($notice);
-
-        if (empty($rsvp)) {
-            // TRANS: Content for a deleted RSVP list item (RSVP stands for "please respond").
-            $out->element('p', null, _m('Deleted.'));
-            return;
-        }
-
-        $out->elementStart('div', 'rsvp');
-        $out->raw($rsvp->asHTML());
-        $out->elementEnd('div');
-        return;
-    }
-}
index aa456c2f9b700890103592f3a9a1dde8ec9c84ae..a5cd823bb76ff14c5e6c37f0ed0c1892a6c409a9 100644 (file)
@@ -48,11 +48,11 @@ class ExtendedProfilePlugin extends Plugin
      *
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m URL mapper
+     * @param URLMapper $m URL mapper
      *
      * @return boolean hook return
      */
-    function onStartInitializeRouter($m)
+    public function onStartInitializeRouter(URLMapper $m)
     {
         $m->connect(
             ':nickname/detail',
index b6c1f16f50c66271983ba9d20a198829b4649fb7..fff5a7621b426b7a49063df2c4ff93de7b8db3ad 100644 (file)
@@ -153,11 +153,11 @@ class FacebookBridgePlugin extends Plugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         // Always add the admin panel route
         $m->connect('panel/facebook', array('action' => 'facebookadminpanel'));
index 9f2618d5821cceaa0104ba933426f55466fb1801..017b78d8b9c366e24f0673ca2fa11236ec6471e2 100644 (file)
@@ -59,6 +59,10 @@ class FavoritePlugin extends ActivityHandlerPlugin
         $user->whereAdd('emailnotifyfav IS NOT NULL');
         if ($user->find()) {
             printfnq("Detected old User table (emailnotifyfav IS NOT NULL). Moving 'emailnotifyfav' property to Profile_prefs...");
+            // First we'll make sure Profile_prefs exists
+            $schema = Schema::get();
+            $schema->ensureTable('profile_prefs', Profile_prefs::schemaDef());
+
             // Make sure we have our own tables setup properly
             while ($user->fetch()) {
                 $user->setPref('email', 'notify_fave', $user->emailnotifyfav);
@@ -393,7 +397,7 @@ class FavoritePlugin extends ActivityHandlerPlugin
             if (empty($arg)) {
                 $result = null;
             } else {
-                list($other, $extra) = $this->split_arg($arg);
+                list($other, $extra) = CommandInterpreter::split_arg($arg);
                 if (!empty($extra)) {
                     $result = null;
                 } else {
@@ -416,7 +420,7 @@ class FavoritePlugin extends ActivityHandlerPlugin
     /**
      * Are we allowed to perform a certain command over the API?
      */
-    public function onCommandSupportedAPI(Command $cmd, array &$supported)
+    public function onCommandSupportedAPI(Command $cmd, &$supported)
     {
         $supported = $supported || $cmd instanceof FavCommand;
     }
index 4bdffc9428e23b34d938919bcc7c706caf3e6629..95df52838846d218ce296052f35bab5444b552a8 100644 (file)
@@ -146,11 +146,6 @@ class NoticeTreeItem extends NoticeListItem
         return;
     }
 
-    function showContext()
-    {
-        return;
-    }
-
     //Just changing the link...
     function showReplyLink()
     {
index 90a1fe5ca04ddd94a054ce0ee1f9bf29b2197c2f..bfb7374d1d6050e5b09ab8d448ea246d679932df 100644 (file)
@@ -29,10 +29,10 @@ class GroupFavoritedPlugin extends Plugin
     /**
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      * @return boolean hook return
      */
-    function onRouterInitialized(Net_URL_Mapper $m)
+    function onRouterInitialized(URLMapper $m)
     {
         $m->connect('group/:nickname/favorited',
                     array('action' => 'groupfavorited'),
index 2fd9e3ef429b71ea211a3d8e978d21ec9133062e..73d7201e6f726c179a5c99041e17945c454373d7 100644 (file)
@@ -70,11 +70,11 @@ class GroupPrivateMessagePlugin extends Plugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('group/:nickname/inbox',
                     array('action' => 'groupinbox'),
index 0a1d6d0da8b0986f4d6702be650e4f5f69727368..effb105e2ba0fcb128ddcd5bc76e3890e7ccfc38 100644 (file)
@@ -66,11 +66,11 @@ class LinkPreviewPlugin extends Plugin
     /**
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m URL mapper
+     * @param URLMapper $m URL mapper
      *
      * @return boolean hook return
      */
-    function onStartInitializeRouter($m)
+    public function onStartInitializeRouter(URLMapper $m)
     {
         $m->connect('main/oembed/proxy',
                 array('action' => 'oembedproxy'));
index 945a649f304c11a814a5508ada031662844983c5..1ca024e9aca29c77d829d90c8a9bdf5cd3761e0d 100644 (file)
@@ -64,11 +64,11 @@ class ModPlusPlugin extends Plugin
      *
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m URL mapper
+     * @param URLMapper $m URL mapper
      *
      * @return boolean hook return
      */
-    function onStartInitializeRouter($m)
+    public function onStartInitializeRouter(URLMapper $m)
     {
         $m->connect('user/remote/:id',
                 array('action' => 'remoteprofile'),
index a57074036abbb4c6c2eb6a10564e135094a81460..07523cdd0b0582166ab24660437aac0e8c45c224 100644 (file)
@@ -48,10 +48,10 @@ class OStatusPlugin extends Plugin
     /**
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      * @return boolean hook return
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         // Discovery actions
         $m->connect('main/ostatustag',
@@ -1320,6 +1320,8 @@ class OStatusPlugin extends Plugin
         if ($magicsig instanceof Magicsig) {
             $xrd->links[] = new XML_XRD_Element_Link(Magicsig::PUBLICKEYREL,
                                 'data:application/magic-public-key,'. $magicsig->toString());
+            $xrd->links[] = new XML_XRD_Element_Link(Magicsig::DIASPORA_PUBLICKEYREL,
+                                base64_encode($magicsig->exportPublicKey()));
         }
 
         // TODO - finalize where the redirect should go on the publisher
@@ -1340,9 +1342,8 @@ class OStatusPlugin extends Plugin
     static public function onCheckActivityAuthorship(Activity $activity, Profile &$profile)
     {
         try {
-            $oprofile = Ostatus_profile::getFromProfile($profile);
-            $oprofile = $oprofile->checkAuthorship($activity);
-            $profile = $oprofile->localProfile();
+            $oprofile = Ostatus_profile::ensureProfileURI($profile->getUri());
+            $profile = $oprofile->checkAuthorship($activity);
         } catch (Exception $e) {
             common_log(LOG_ERR, 'Could not get a profile or check authorship ('.get_class($e).': "'.$e->getMessage().'") for activity ID: '.$activity->id);
             $profile = null;
index 289865a97f692eaad1fc4951e85302304cc9e4bb..be87052ac3e82fe58a6c22d9ae95ceb5c0c7531c 100644 (file)
@@ -36,6 +36,7 @@ require_once 'Crypt/RSA.php';
 class Magicsig extends Managed_DataObject
 {
     const PUBLICKEYREL = 'magic-public-key';
+    const DIASPORA_PUBLICKEYREL = 'diaspora-public-key';
 
     public $__table = 'magicsig';
 
@@ -184,6 +185,12 @@ class Magicsig extends Managed_DataObject
         return 'RSA.' . $mod . '.' . $exp . $private_exp;
     }
 
+    public function exportPublicKey($format=CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
+    {
+        $this->publicKey->setPublicKey();
+        return $this->publicKey->getPublicKey($format);
+    }
+
     /**
      * importKeys will load the object's keypair string, which initiates
      * loadKey() and configures Crypt_RSA objects.
index adc33263363ecaa651b74b6a87d759bdb604376f..96ab7f6be72ab4cef7bb78d83ec2f183ab4d5b69 100644 (file)
@@ -88,6 +88,10 @@ class Ostatus_profile extends Managed_DataObject
      */
     public function localProfile()
     {
+        if ($this->isGroup()) {
+            return $this->localGroup()->getProfile();
+        }
+
         $profile = Profile::getKV('id', $this->profile_id);
         if ($profile instanceof Profile) {
             return $profile;
@@ -731,7 +735,7 @@ class Ostatus_profile extends Managed_DataObject
     {
         $notice = null;
 
-        $profile = $this->checkAuthorship($activity, $this->localProfile());
+        $profile = ActivityUtils::checkAuthorship($activity, $this->localProfile());
 
         // It's not always an ActivityObject::NOTE, but... let's just say it is.
 
@@ -844,6 +848,10 @@ class Ostatus_profile extends Managed_DataObject
                     $options['reply_to'] = $orig->id;
                 }
             }
+            if (!empty($activity->context->conversation)) {
+                // we store the URI here, Notice class can look it up later
+                $options['conversation'] = $activity->context->conversation;
+            }
 
             $location = $activity->context->location;
             if ($location) {
@@ -1922,7 +1930,7 @@ class Ostatus_profile extends Managed_DataObject
         }
 
         // Try looking it up
-        $oprofile = Ostatus_profile::getKV('uri', 'acct:'.$addr);
+        $oprofile = Ostatus_profile::getKV('uri', Discovery::normalize($addr));
 
         if ($oprofile instanceof Ostatus_profile) {
             self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), $oprofile->getUri());
@@ -2150,7 +2158,7 @@ class Ostatus_profile extends Managed_DataObject
                 common_log(LOG_WARNING,
                     "OStatus: skipping post with group listed ".
                     "as author: " . $oprofile->getUri() . " in feed from " . $this->getUri());
-                return false;
+                throw new ServerException('Activity author is a non-actor');
             }
         } else {
             $actor = $activity->actor;
index 5adb56662619694c625bd9449fb94cb81c2146d9..fab35fe2f4eafb09faa95ffc54d374330b45a7d7 100644 (file)
@@ -68,11 +68,11 @@ class OpenIDPlugin extends Plugin
      *
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m URL mapper
+     * @param URLMapper $m URL mapper
      *
      * @return boolean hook return
      */
-    function onStartInitializeRouter($m)
+    public function onStartInitializeRouter(URLMapper $m)
     {
         $m->connect('main/openid', array('action' => 'openidlogin'));
         $m->connect('main/openidtrust', array('action' => 'openidtrust'));
index ff98bcfb307e745050fc1bd36550f70650378281..92886dcc28defac7a39bb83d5a9b0a842fe69dcb 100644 (file)
@@ -86,11 +86,11 @@ class PollPlugin extends MicroAppPlugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('main/poll/new',
                     array('action' => 'newpoll'));
@@ -137,11 +137,6 @@ class PollPlugin extends MicroAppPlugin
         return array(self::POLL_OBJECT, self::POLL_RESPONSE_OBJECT);
     }
 
-
-    function adaptNoticeListItem($nli) {
-        return new PollListItem($nli);
-    }
-
     /**
      * When a notice is deleted, delete the related Poll
      *
@@ -445,4 +440,27 @@ class PollPlugin extends MicroAppPlugin
 
         return true;
     }
+
+    protected function showNoticeContent(Notice $stored, HTMLOutputter $out, Profile $scoped=null)
+    {
+        if ($stored->object_type == self::POLL_RESPONSE_OBJECT) {
+            parent::showNoticeContent($stored, $out, $scoped);
+            return;
+        }
+
+        // If the stored notice is a POLL_OBJECT
+        $poll = Poll::getByNotice($stored);
+        if ($poll instanceof Poll) {
+            if (!$scoped instanceof Profile || $poll->getResponse($scoped) instanceof Poll_response) {
+                // Either the user is not logged in or it has already responded; show the results.
+                $form = new PollResultForm($poll, $out);
+            } else {
+                $form = new PollResponseForm($poll, $out);
+            }
+            $form->show();
+        } else {
+            // TRANS: Error text displayed if no poll data could be found.
+            $out->text(_m('Poll data is missing'));
+        }
+    }
 }
diff --git a/plugins/Poll/lib/polllistitem.php b/plugins/Poll/lib/polllistitem.php
deleted file mode 100644 (file)
index 875fa9c..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Adapter to show polls in a nicer way
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Poll
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET')) {
-    // This check helps protect against security problems;
-    // your code file can't be executed directly from the web.
-    exit(1);
-}
-
-/**
- * An adapter to show polls in a nicer way
- *
- * @category  Poll
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link      http://status.net/
- */
-
-class PollListItem extends NoticeListItemAdapter
-{
-    // @fixme which domain should we use for these namespaces?
-    const POLL_OBJECT          = 'http://activityschema.org/object/poll';
-    const POLL_RESPONSE_OBJECT = 'http://activityschema.org/object/poll-response';
-
-    function showNotice(Notice $notice, $out)
-    {
-        switch ($notice->object_type) {
-        case self::POLL_OBJECT:
-            return $this->showNoticePoll($notice, $out);
-        case self::POLL_RESPONSE_OBJECT:
-            return $this->showNoticePollResponse($notice, $out);
-        default:
-            // TRANS: Exception thrown when performing an unexpected action on a poll.
-            // TRANS: %s is the unexpected object type.
-            throw new Exception(sprintf(_m('Unexpected type for poll plugin: %s.'), $notice->object_type));
-        }
-    }
-
-    function showNoticePoll(Notice $notice, $out)
-    {
-        $user = common_current_user();
-
-        // @hack we want regular rendering, then just add stuff after that
-        $nli = new NoticeListItem($notice, $out);
-        $nli->showNotice();
-
-        $out->elementStart('div', array('class' => 'e-content poll-content'));
-        $poll = Poll::getByNotice($notice);
-        if ($poll) {
-            if ($user) {
-                $profile = $user->getProfile();
-                $response = $poll->getResponse($profile);
-                if ($response) {
-                    // User has already responded; show the results.
-                    $form = new PollResultForm($poll, $out);
-                } else {
-                    $form = new PollResponseForm($poll, $out);
-                }
-                $form->show();
-            }
-        } else {
-            // TRANS: Error text displayed if no poll data could be found.
-            $out->text(_m('Poll data is missing'));
-        }
-        $out->elementEnd('div');
-
-        // @fixme
-        $out->elementStart('div', array('class' => 'e-content'));
-    }
-
-    function showNoticePollResponse(Notice $notice, $out)
-    {
-        $user = common_current_user();
-
-        // @hack we want regular rendering, then just add stuff after that
-        $nli = new NoticeListItem($notice, $out);
-        $nli->showNotice();
-
-        // @fixme
-        $out->elementStart('div', array('class' => 'e-content'));
-    }
-}
index 1cbab3b60b30d19ce9b98e3b2b89185476b771f9..bdd54afd2ea7ca995c394be2a1995017fab0ba37 100644 (file)
@@ -75,12 +75,12 @@ class QnAPlugin extends MicroAppPlugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
 
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $UUIDregex = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}';
 
@@ -339,7 +339,7 @@ class QnAPlugin extends MicroAppPlugin
         $nli->showNoticeLink();
         $nli->showNoticeSource();
         $nli->showNoticeLocation();
-        $nli->showContext();
+        $nli->showPermalink();
         $nli->showRepeat();
 
         $nli->showNoticeOptions();
index b0b79fd1c622fc61a7bd6bc203a0d2082440a67a..25fa921ffec9709047f8f555d84b13a040be9879 100644 (file)
@@ -71,10 +71,10 @@ class RealtimePlugin extends Plugin
     /**
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      * @return boolean hook return
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('main/channel/:channelkey/keepalive',
                     array('action' => 'keepalivechannel'),
index 0a0e50b3606c2d6330c0fe9f4dbf6a68b4f97038..8758013a4147fc85dd7f98906df5a88405190c9a 100644 (file)
@@ -182,11 +182,11 @@ class SamplePlugin extends Plugin
      * action will be named 'FoobarAction', where action = 'foobar'. The class
      * must be loaded in the onAutoload() method.
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('main/hello',
                     array('action' => 'hello'));
index ba25bf1b2b52dab9cafdce1208b7b9fe46e391ed..dc7ff7b19a2fff843bb2db3e85ec3d696cd0d2af 100644 (file)
@@ -63,11 +63,11 @@ class SearchSubPlugin extends Plugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('search/:search/subscribe',
                     array('action' => 'searchsub'),
index ca165893167fd7989d9181dfab977ee25c7c74b6..3d83629bb2dc1acfa59b6f2d1e61bcaf6d6d752d 100644 (file)
@@ -68,11 +68,11 @@ class SitemapPlugin extends Plugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('sitemapindex.xml',
                     array('action' => 'sitemapindex'));
index b3cf058a05d2eb5f36708d27adfc72d8f93b58a6..92d1f55c3f5d365bcb50d2d36601a57dfa6ba0fd 100644 (file)
@@ -52,10 +52,10 @@ class SlicedFavoritesPlugin extends Plugin
     /**
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      * @return boolean hook return
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('favorited/:slice',
                     array('action' => 'favoritedslice'),
index b0f95125f30f7defa46dedbe59273edbec1ec792..a21cb4355131d5c658fac811b27dcd566563d409 100644 (file)
@@ -28,10 +28,10 @@ class SubMirrorPlugin extends Plugin
     /**
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      * @return boolean hook return
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('settings/mirror',
                     array('action' => 'mirrorsettings'));
index 1c493de0cd5e04e9540c381a1246b0869911258c..ef58553d2eb3f28a548d251efcfdc977ab98c490 100644 (file)
@@ -63,11 +63,11 @@ class TagSubPlugin extends Plugin
     /**
      * Map URLs to actions
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook value; true means continue processing, false means stop.
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('tag/:tag/subscribe',
                     array('action' => 'tagsub'),
index cb3369d1d09ce190680940186a574872b8f17fb2..4f1f15c377b3eaac7d1df50a82a833f784be2690 100644 (file)
@@ -14,13 +14,12 @@ Installation
 ------------
 
 OAuth 1.0a (http://oauth.net) is used to to access protected resources
-on Twitter (as opposed to HTTP Basic Auth)*.  To use Twitter bridging
-you will need to register your instance of StatusNet as an application
-on Twitter (http://twitter.com/apps).  During the application
-registration process your application will be assigned a "consumer" key
-and secret, which the plugin will use to make OAuth requests to Twitter.
-You can either pass the consumer key and secret in when you enable the
-plugin, or set it using the Twitter administration panel**.
+on Twitter. To use Twitter bridging you will need to register your
+instance of StatusNet as an application on Twitter (http://twitter.com/apps).
+During the application registration process your application will be assigned
+a "consumer" key and secret, which the plugin will use to make OAuth requests
+to Twitter. You can either pass the consumer key and secret in when you
+enable the plugin, or set it using the Twitter administration panel.
 
 When registering your application with Twitter set the type to "Browser"
 and your Callback URL to:
@@ -42,52 +41,26 @@ To enable the plugin, add the following to your config.php:
         )
     );
 
-or just:
+or if you want to set the variables from the website's administration panel:
 
    addPlugin('TwitterBridge');
 
-if you want to set the consumer key and secret from the Twitter bridge
-administration panel.  (The Twitter bridge wont work at all
-unless you configure it with a consumer key and secret.)
-
-* Note: The plugin will still push notices to Twitter for users who
-  have previously set up the Twitter bridge using their Twitter name and
-  password under an older version of StatusNet, but all new Twitter
-  bridge connections will use OAuth.
-
-** For multi-site setups you can also set a global consumer key and
-   secret.  The Twitter bridge will fall back on the global key pair if
-   it can't find a local pair, e.g.:
-
-   $config['twitter']['global_consumer_key']    = 'YOUR_CONSUMER_KEY';
-   $config['twitter']['global_consumer_secret'] = 'YOUR_CONSUMER_SECRET';
-
-Upgrade
--------
-
-If you've used the Twitter bridge plugin prior to version 0.9.5,
-you'll need to run the new scripts/initialize_notice_to_status.php
-script to initialize the new notice-to-status mapping file, which
-greatly improves the integration between StatusNet and Twitter.
+After saving your configuration file, please run 'php scripts/upgrade.php'
+and also restart the background daemons if they are active on your instance.
 
 Administration panel
 --------------------
 
-As of StatusNet 0.9.0 there is a new administration panel that allows
-you to configure Twitter bridge settings within StatusNet itself,
-instead of having to specify them manually in your config.php.
-
-To access it, you'll need to use a user with the "administrator"
-role (see: scripts/userrole.php).
+To access the administration panel, you'll need to use a user with the
+"administrator" role (see: scripts/userrole.php).
 
 Sign in with Twitter
 --------------------
 
-With 0.9.0, StatusNet optionally allows users to register and
-authenticate using their Twitter credentials via the "Sign in with
-Twitter" pattern described here:
+GNU social optionally allows users to register and authenticate using their
+Twitter credentials via the "Sign in with Twitter" pattern described here:
 
-    http://apiwiki.twitter.com/Sign-in-with-Twitter
+    https://dev.twitter.com/web/sign-in
 
 The option is _on_ by default when you install the plugin, but it can
 disabled via the Twitter bridge administration panel, or by adding the
index 8d14744090ab0c5a734e5264b40fba4a31c43c79..643591cf775e1fb8d62ad6c75964e43e78c656b8 100644 (file)
@@ -107,11 +107,11 @@ class TwitterBridgePlugin extends Plugin
      *
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      *
      * @return boolean hook return
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('panel/twitter', array('action' => 'twitteradminpanel'));
 
index 490a08f4a8e64fc3362bfb76da179be924ddd857..a5fc470e079e19af0d9294837945130f8b0656cf 100644 (file)
@@ -67,11 +67,11 @@ class UserFlagPlugin extends Plugin
     /**
      * Add our actions to the URL router
      *
-     * @param Net_URL_Mapper $m URL mapper for this hit
+     * @param URLMapper $m URL mapper for this hit
      *
      * @return boolean hook return
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('main/flag/profile', array('action' => 'flagprofile'));
         $m->connect('main/flag/clear', array('action' => 'clearflag'));
index 9d6c5ad41e850847e2a9154e3f0121c578bc4176..f11ebfbfac4e6da6693bbf8616b0f1f767d516ef 100644 (file)
@@ -29,10 +29,10 @@ class YammerImportPlugin extends Plugin
     /**
      * Hook for RouterInitialized event.
      *
-     * @param Net_URL_Mapper $m path-to-action mapper
+     * @param URLMapper $m path-to-action mapper
      * @return boolean hook return
      */
-    function onRouterInitialized($m)
+    public function onRouterInitialized(URLMapper $m)
     {
         $m->connect('panel/yammer',
                     array('action' => 'yammeradminpanel'));
index 6cbb8c28aa406aa140cca13803495c44115e3c6e..624043161da9f19fe0e3512e760e0f770e3f2ca4 100644 (file)
@@ -186,6 +186,7 @@ function newNotice($i, $tagmax)
     $notice = Notice::saveNew($user->id, $content, 'createsim', $options);
 }
 
+/* Plugins should be part of the simulation too!
 function newMessage($i)
 {
     global $userprefix;
@@ -206,7 +207,7 @@ function newMessage($i)
     $other = $friends[$j];
 
     $message = Message::saveNew($user->id, $other->id, $content, 'createsim');
-}
+}*/
 
 function newSub($i)
 {
@@ -345,7 +346,7 @@ function testNoticeContent()
 }
 
 //function main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $favesavg, $messageavg, $tagmax)
-function main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $messageavg, $tagmax)
+function main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $tagmax)
 {
     global $config;
     $config['site']['dupelimit'] = -1;
@@ -374,7 +375,7 @@ function main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $message
     // # registrations + # notices + # subs
 
     //$events = $usercount + $groupcount + ($usercount * ($noticeavg + $subsavg + $joinsavg + $favesavg + $messageavg));
-    $events = $usercount + $groupcount + ($usercount * ($noticeavg + $subsavg + $joinsavg + $messageavg));
+    $events = $usercount + $groupcount + ($usercount * ($noticeavg + $subsavg + $joinsavg));
 
     $events -= $preuser;
     $events -= $pregroup;
@@ -385,9 +386,10 @@ function main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $message
     $st = $nt + ($usercount * $subsavg);
     $jt = $st + ($usercount * $joinsavg);
 //    $ft = $jt + ($usercount * $favesavg);
-    $mt = $ft + ($usercount * $messageavg);
+//    $mt = $ft + ($usercount * $messageavg);
 
-    printfv("$events events ($ut, $gt, $nt, $st, $jt, $ft, $mt)\n");
+//    printfv("$events events ($ut, $gt, $nt, $st, $jt, $ft, $mt)\n");
+    printfv("$events events ($ut, $gt, $nt, $st, $jt)\n");
 
     for ($i = 0; $i < $events; $i++)
     {
@@ -413,9 +415,9 @@ function main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $message
 /*        } else if ($e > $jt && $e <= $ft) {
             printfv("$i Making a new fave\n");
             newFave($n);*/
-        } else if ($e > $ft && $e <= $mt) {
+/*        } else if ($e > $ft && $e <= $mt) {
             printfv("$i Making a new message\n");
-            newMessage($n);
+            newMessage($n);*/
         } else {
             printfv("No event for $i!");
         }
@@ -430,7 +432,7 @@ $noticeavg   = (have_option('n', 'notices')) ? get_option_value('n', 'notices')
 $subsavg     = (have_option('b', 'subscriptions')) ? get_option_value('b', 'subscriptions') : max($usercount/20, 10);
 $joinsavg    = (have_option('j', 'joins')) ? get_option_value('j', 'joins') : 5;
 //$favesavg    = (have_option('f', 'faves')) ? get_option_value('f', 'faves') : max($noticeavg/10, 5);
-$messageavg  = (have_option('m', 'messages')) ? get_option_value('m', 'messages') : max($noticeavg/10, 5);
+//$messageavg  = (have_option('m', 'messages')) ? get_option_value('m', 'messages') : max($noticeavg/10, 5);
 $tagmax      = (have_option('t', 'tags')) ? get_option_value('t', 'tags') : 10000;
 $userprefix  = (have_option('x', 'prefix')) ? get_option_value('x', 'prefix') : 'testuser';
 $groupprefix = (have_option('z', 'groupprefix')) ? get_option_value('z', 'groupprefix') : 'testgroup';
@@ -448,7 +450,7 @@ if (is_readable($wordsfile)) {
 
 try {
     //main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $favesavg, $messageavg, $tagmax);
-    main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $messageavg, $tagmax);
+    main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $tagmax);
 } catch (Exception $e) {
     printfv("Got an exception: ".$e->getMessage());
 }
index bd4a73d3af65350ec18f70ee413634ac32d42198..c221a495af1cc04489643ce24bb3ce8a10bc1cd8 100644 (file)
@@ -34,6 +34,8 @@ require_once INSTALLDIR.'/scripts/commandline.inc';
 function main()
 {
     if (Event::handle('StartUpgrade')) {
+        fixupConversationURIs();
+
         updateSchemaCore();
         updateSchemaPlugins();
 
@@ -199,6 +201,29 @@ function initConversation()
     printfnq("DONE.\n");
 }
 
+function fixupConversationURIs()
+{
+    printfnq("Ensuring all conversations have a URI...");
+
+    $conv = new Conversation();
+    $conv->whereAdd('uri IS NULL');
+
+    if ($conv->find()) {
+        $rounds = 0;
+        while ($conv->fetch()) {
+            $uri = common_local_url('conversation', array('id' => $conv->id));
+            $sql = sprintf('UPDATE conversation SET uri="%1$s" WHERE id="%2$d";',
+                            $conv->escape($uri), $conv->id);
+            $conv->query($sql);
+            if (($conv->N-++$rounds) % 500 == 0) {
+                printfnq(sprintf(' %d items left...', $conv->N-$rounds));
+            }
+        }
+    }
+
+    printfnq("DONE.\n");
+}
+
 function initGroupProfileId()
 {
     printfnq("Ensuring all User_group entries have a Profile and profile_id...");
index 1029850a1e654fa8b46144a802f420da1b36f759..631a62ea5dca35ad81d80bae3bb14fed0c4e291b 100644 (file)
@@ -49,11 +49,11 @@ h1, h2, h3, h4, h5, h6 {
     margin-bottom: 15px;
 }
 
-h1 {font-size: 2.2em;}
-h2 {font-size: 1.8em;}
-h3 {font-size: 1.6em;}
-h4 {font-size: 1.4em;}
-h5 {font-size: 1.2em;}
+h1 {font-size: 2.0em;}
+h2 {font-size: 1.6em;}
+h3 {font-size: 1.4em;}
+h4 {font-size: 1.2em;}
+h5 {font-size: 1.1em;}
 h6 {font-size: 1em;}
 
 p {
@@ -567,6 +567,10 @@ address .poweredby {
     z-index: 1;
 }
 
+.form_settings {
+    clear: both;
+}
+
 /* site nav local views */
 
 
@@ -983,6 +987,18 @@ content: ":";
     display: none;
 }
 
+.notice .permalink:after {
+    content: ']';
+}
+
+.notice .permalink:before {
+    content: '[';
+}
+
+.notice .permalink.external {
+    display: none;
+}
+
 /* old school conversation style */
 
 #conversation .notices .notices {
@@ -1303,20 +1319,16 @@ form label.submit {
 display:none;
 }
 
-.form_settings {
-    clear:both;
-}
-
 .form_settings fieldset {
     margin-top: 10px;
-    margin-bottom: 30px;
+    margin-bottom: 10px;
     border: none;
 }
 
 .form_settings fieldset fieldset {
-    margin-bottom: 40px;
+    margin-bottom: 20px;
     padding: 10px;
-    padding-top: 30px;
+    padding-top: 10px;
     border-width:1px;
     border-style:solid;
     background:rgba(240, 240, 240, 0.2);
@@ -1351,9 +1363,6 @@ float:left;
 }
 
 
-.form_settings .form_data input {
-width:39%;
-}
 .form_settings .form_data input.submit,
 .form_settings .form_data input.checkbox,
 .form_settings .form_data input.radio {
index a46f296537db20e52e0ab8b04d68f8b33fc8ea2c..69d9eded49dcf4f2389abe84a5d4d063b57d81ae 100644 (file)
@@ -48,13 +48,6 @@ a:hover {color: blue;}
 
 abbr {border-bottom: none;}
 
-h1 {font-size: 1.6em;}
-h2 {font-size: 1.6em;}
-h3 {font-size: 1.4em;}
-h4 {font-size: 1.4em;}
-h5 {font-size: 1.2em;}
-h6 {font-size: 1em;}
-
 #wrap {
     background: #fff url('../images/brdr_black_dot.png') repeat-x 0px 10px;
 }