code:
<?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('GNUSOCIAL')) { 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 (!$this->scoped instanceof Profile) {
            // 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->scoped->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->scoped->getID() === $this->other->getID()) {

            // 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->scoped->getID(),
            $this->other->getID(),
            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);
        }
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * GNUsocial implementation of Direct Messages
 *
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

defined('GNUSOCIAL') || die();

/**
 * Action handler for the inbox
 *
 * @category  Plugin
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class InboxAction extends MailboxAction
{
    /**
     * Title of the page.
     *
     * @return string page title
     */
    function title() : string
    {
        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(_m('Inbox for %1$s - page %2$d'), $this->user->getNickname(),
                $this->page);
        } else {
            // TRANS: Title for the first page of the inbox page.
            // TRANS: %s is the user's nickname.
            return sprintf(_m('Inbox for %s'), $this->user->getNickname());
        }
    }

    /**
     * Retrieve the messages for this user and this page.
     *
     * @return Notice data object with stream for messages
     */
    function getMessages()
    {
        return MessageModel::inboxMessages($this->user, $this->page);
    }

    /**
     * Retrieve inbox MessageList widget
     */
    function getMessageList($message)
    {
        return new InboxMessageList($this, $message);
    }

    /**
     * Instructions for using this page.
     *
     * @return string localised instructions for using the page
     */
    function getInstructions() : string
    {
        // TRANS: Instructions for user inbox page.
        return _m('This is your inbox, which lists your incoming private messages.');
    }
}

repo_name: spookie/gnu

license: mit


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * GNUsocial implementation of Direct Messages
 *
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

defined('GNUSOCIAL') || die();

/**
 * Action for posting new direct messages
 *
 * @category Plugin
 * @package  GNUsocial
 * @author   Evan Prodromou <evan@status.net>
 * @author   Zach Copley <zach@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @author   Bruno Casteleiro <brunoccast@fc.up.pt>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class NewmessageAction extends FormAction
{
    protected $form     = 'Message';
    protected $to       = null;
    protected $content  = null;

    /**
     * Title of the page.
     * Note that this usually doesn't get called unless something went wrong.
     *
     * @return string page title
     */
    function title() : string
    {
        // TRANS: Page title for new direct message page.
        return _('New message');
    }

    protected function doPreparation()
    {
        if ($this->trimmed('to')) {
            $this->to = Profile::getKV('id', $this->trimmed('to'));
            if (!$this->to instanceof Profile) {
                // TRANS: Client error displayed trying to send a direct message to a non-existing user.
                $this->clientError(_('No such user.'), 404);
            }

            $this->formOpts['to'] = $this->to;
        }

        if ($this->trimmed('content')) {
            $this->content = $this->trimmed('content');
            $this->formOpts['content'] = $this->content;
        }

        if ($this->trimmed('to-box')) {
            $selected = explode(':', $this->trimmed('to-box'));

            if (sizeof($selected) == 2) {
                $this->to = Profile::getKV('id', $selected[1]);
                // validating later
            }
        }
    }

    protected function doPost()
    {
        assert($this->scoped instanceof Profile); // XXX: maybe an error instead...

        if (empty($this->content)) {
            // TRANS: Form validator error displayed trying to send a direct message without content.
            $this->clientError(_('No content!'));
        }

        $content_shortened = $this->scoped->shortenLinks($this->content);

        if (MessageModel::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.',
                                       MessageModel::maxContent()),
                                    MessageModel::maxContent()));
        }

        // validate recipients
        if (!$this->to instanceof Profile) {
            $mentions = common_find_mentions($this->content, $this->scoped);
            if (empty($mentions)) {
                $this->clientError(_('No recipients specified.'));
            }
        } else {
            // push to-box profile to the content message, will be
            // detected during Notice save
            try {
                if ($this->to->isLocal()) {
                    $this->content = "@{$this->to->getNickname()} {$this->content}";
                } else {
                    $this->content = '@' . substr($this->to->getAcctUri(), 5) . " {$this->content}";
                }
            } catch (ProfileNoAcctUriException $e) {
                // well, I'm no magician
            }
        }

        $message = MessageModel::saveNew($this->scoped, $this->content);
        Event::handle('SendDirectMessage', [$message]);
        mail_notify_message($message);

        if (GNUsocial::isAjax()) {
            // TRANS: Confirmation text after sending a direct message.
            // TRANS: %s is the direct message recipient.
            return sprintf(_('Direct message to %s sent.'), $this->to->getNickname());
        }

        $url = common_local_url('outbox', array('nickname' => $this->scoped->getNickname()));
        common_redirect($url, 303);
    }

    function showNoticeForm()
    {
        // Just don't show a NoticeForm
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * GNUsocial implementation of Direct Messages
 *
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

defined('GNUSOCIAL') || die();

/**
 * Action handler for the outbox
 *
 * @category  Plugin
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class OutboxAction extends MailboxAction
{
    /**
     * Title of the page
     *
     * @return string page title
     */
    function title() : string
    {
        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(_m('Outbox for %1$s - page %2$d'),
                $this->user->getNickname(), $page);
        } else {
            // TRANS: Title for first page of outbox.
            return sprintf(_m('Outbox for %s'), $this->user->getNickname());
        }
    }

    /**
     * Retrieve the messages for this user and this page.
     *
     * @return Notice data object with stream for messages
     */
    function getMessages()
    {
        return MessageModel::outboxMessages($this->user, $this->page);
    }

    /**
     * Retrieve outbox MessageList widget.
     */
    function getMessageList($message)
    {
        return new OutboxMessageList($this, $message);
    }

    /**
     * Instructions for using this page.
     *
     * @return string localised instructions for using the page
     */
    function getInstructions() : string
    {
        // TRANS: Instructions for outbox.
        return _m('This is your outbox, which lists private messages you have sent.');
    }
}

/**
 * Outbox MessageList widget
 *
 * @category  Plugin
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class OutboxMessageList extends MessageList
{
    function newItem($message)
    {
        return new OutboxMessageListItem($this->out, $message);
    }
}

/**
 * Outbox MessageListItem widget
 *
 * @category  Plugin
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class OutboxMessageListItem extends MessageListItem
{
    /**
     * Returns the profile we want to show with the message
     *
     * Note that the plugin now handles sending for multiple profiles,
     * but since the UI isn't changed yet, we still retrieve a single
     * profile from this function (or null, if for blocking reasons
     * there are no attentions stored).
     *
     * @return Profile|null
     */
    function getMessageProfile() : ?Profile
    {
        $attentions = $this->message->getAttentionProfiles();
        return empty($attentions) ? null : $attentions[0];
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * GNUsocial implementation of Direct Messages
 *
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

defined('GNUSOCIAL') || die();

/**
 * Action for showing a single message
 *
 * @category  Plugin
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class ShowmessageAction extends Action
{
    protected $message    = null;
    protected $from       = null;
    protected $attentions = null;
    protected $user       = null;

    /**
     * Load attributes based on database arguments.
     *
     * @param array $args $_REQUEST array
     * @return bool success flag
     */
    function prepare($args = [])
    {
        parent::prepare($args);

        if (!$this->trimmed('message')) {
            return true;
        }

        $this->message = Notice::getKV('id', $this->trimmed('message'));

        if (!$this->message instanceof Notice) {
            // TRANS: Client error displayed requesting a single message that does not exist.
            $this->clientError(_m('No such message.'), 404);
        }

        $this->from       = $this->message->getProfile();
        $this->attentions = $this->message->getAttentionProfiles();

        $this->user = common_current_user();

        if (empty($this->user) || $this->user->getID() != $this->from->getID()) {

            $receiver = false;
            foreach ($this->attentions as $attention) {
                if ($this->user->getID() == $attention->getID()) {
                    $receiver = true;
                    break;
                }
            }

            if (!$receiver) {
                // TRANS: Client error displayed requesting a single direct message the requesting user was not a party in.
                throw new ClientException(_m('Only the sender and recipients may read this message.'), 403);
            }
        }

        return true;
    }

    /**
     * Handler method.
     *
     * @return void
     */
    function handle()
    {
        $this->showPage();
    }

    /**
     * Title of the page.
     *
     * @return string page title
     */
    function title() : string
    {
        if ($this->user->getID() == $this->from->getID()) {
            if (sizeof($this->attentions) > 1) {
                return sprintf(_m('Message to many on %1$s'), common_exact_date($this->message->getCreated()));
            } else {
                $to = Profile::getKV('id', $this->attentions[0]->getID());
                // @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(_m('Message to %1$s on %2$s'),
                               $to->getBestName(),
                               common_exact_date($this->message->getCreated()));
            }
        } else {
            // @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(_m('Message from %1$s on %2$s'),
                            $this->from->getBestName(),
                            common_exact_date($this->message->getCreated()));
        }
    }

    /**
     * Show content.
     *
     * @return void
     */
    function showContent()
    {
        $this->elementStart('ul', 'notices messages');
        $ml = new ShowMessageListItem($this, $this->message, $this->user, $this->from, $this->attentions);
        $ml->show();
        $this->elementEnd('ul');
    }

    /**
     * Is this action read-only?
     *
     * @param array $args other arguments
     * @return bool true if read-only action, false otherwise
     */
    function isReadOnly($args) : bool
    {
        return true;
    }

    /**
     * Don't show aside
     *
     * @return void
     */
    function showAside() {

    }
}

/**
 * showmessage action's MessageListItem widget.
 *
 * @category  Plugin
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class ShowMessageListItem extends MessageListItem
{
    protected $user;
    protected $from;
    protected $attentions;

    function __construct($out, $message, $user, $from, $attentions)
    {
        parent::__construct($out, $message);

        $this->user       = $user;
        $this->from       = $from;
        $this->attentions = $attentions;
    }

    function getMessageProfile() : ?Profile
    {
        return $this->user->getID() == $this->from->getID() ?
               $this->attentions[0] : $this->from;
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * GNUsocial implementation of Direct Messages
 *
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

defined('GNUSOCIAL') || die();

/**
 * Table definition for message.
 *
 * Since the new updates this class only has the necessary
 * logic to upgrade te plugin.
 *
 * @category  Plugin
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
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(191)  unique_key   not 255 because utf8mb4 takes more space
    public $from_profile;                    // int(4)   not_null
    public $to_profile;                      // int(4)   not_null
    public $content;                         // text()
    public $rendered;                        // text()
    public $url;                             // varchar(191)   not 255 because utf8mb4 takes more space
    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' => 191, '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' => 191, '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);
    }

    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->verb = ActivityVerb::POST;
            $act->time = strtotime($this->created);

            $actor_profile = $this->getFrom();
            if (is_null($actor_profile)) {
                throw new Exception(sprintf("Sender profile not found: %d", $this->from_profile));
            }
            $act->actor = $actor_profile->asActivityObject();

            $act->context = new ActivityContext();
            $options = ['source' => $this->source,
                        'uri'    => TagURI::mint(sprintf('activity:message:%d', $this->id)),
                        'url'    => $this->uri,
                        'scope'  => Notice::MESSAGE_SCOPE];

            $to_profile = $this->getTo();
            if (is_null($to_profile)) {
                throw new Exception(sprintf("Receiver profile not found: %d", $this->to_profile));
            }
            $act->context->attention[$to_profile->getUri()] = ActivityObject::PERSON;

            $act->objects[] = ActivityObject::fromMessage($this);

            $source = $this->getSource();
            if ($source instanceof Notice_source) {
                $act->generator = ActivityObject::fromNoticeSource($source);
            }

            Event::handle('EndMessageAsActivity', array($this, &$act));
        }

        return $act;
    }
}


code:
<?php

if (!defined('GNUSOCIAL')) { exit(1); }

class InboxMessageList extends MessageList
{
    function newItem($message)
    {
        return new InboxMessageListItem($this->out, $message);
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * GNUsocial implementation of Direct Messages
 *
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

defined('GNUSOCIAL') || die();

/**
 * Inbox MessageListItem widget
 *
 * @category  Plugin
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class InboxMessageListItem extends MessageListItem
{
    /**
     * Returns the profile we want to show with the message
     *
     * @return Profile The profile that matches the message
     */
    function getMessageProfile(): ?Profile
    {
        return $this->message->getProfile();
    }
}


code:
<?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(array $args = array())
    {
        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()
    {
        parent::handle();

        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();
    }
}


code:
<?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');
    }
}


code:
<?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());
        }
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * GNUsocial implementation of Direct Messages
 *
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

defined('GNUSOCIAL') || die();

/**
 * Form for posting a direct message
 *
 * @category  Plugin
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class MessageForm extends Form
{
    protected $to      = null;
    protected $content = null;

    /**
     * Constructor.
     *
     * @param HTMLOutputter $out output channel
     * @param array|null $formOpts
     */
    function __construct(HTMLOutputter $out = null, ?array $formOpts = null)
    {
        parent::__construct($out);

        if (isset($formOpts['to'])) {
            $this->to = $formOpts['to'];
        }

        $this->content = $formOpts['content'] ?? '';
    }

    /**
     * ID of the form.
     *
     * @return string ID of the form
     */
    function id(): string
    {
        return 'form_notice-direct';
    }

    /**
     * Class of the form.
     *
     * @return string class of the form
     */
    function formClass(): string
    {
        return 'form_notice ajax-notice';
    }

    /**
     * Action of the form.
     *
     * @return string URL of the action
     */
    function action(): string
    {
        return common_local_url('newmessage');
    }

    /**
     * Legend of the Form.
     *
     * @return void
     */
    function formLegend()
    {
        // TRANS: Form legend for direct notice.
        $this->out->element('legend', null, _m('Send a direct notice'));
    }

    /**
     * Data elements.
     *
     * @return void
     */
    function formData()
    {
        $user = common_current_user();

        $recipients = [];
        $default    = 'default';

        $subs   = $user->getSubscribed();
        $n_subs = 0;

        // Add local-subscriptions
        while ($subs->fetch()) {
            $n_subs++;
            if ($subs->isLocal()) {
                $value = 'profile:'.$subs->getID();
                try {
                    $recipients[$value] = substr($subs->getAcctUri(), 5) . " [{$subs->getBestName()}]";
                } catch (ProfileNoAcctUriException $e) {
                    $recipients[$value] = "[?@?] " . $e->profile->getBestName();
                }
            }
        }

        if (sizeof($recipients) < $n_subs) {
            // some subscriptions aren't local and therefore weren't added,
            // worth checking if others want to add them
            Event::handle('FillDirectMessageRecipients', [$user, &$recipients]);
        }

        // if we came from a profile page, then lets make the message receiver visible
        if (!is_null($this->to)) {
            if (isset($recipients['profile:'.$this->to->getID()])) {
                $default = 'profile' . $this->to->getID();
            } else {
                try {
                    if ($this->to->isLocal()) {
                        $this->content = "@{$this->to->getNickname()} {$this->content}";
                    } else {
                        $this->content = substr($this->to->getAcctUri(), 5) . " {$this->content}";
                    }
                } catch (ProfileNoAcctUriException $e) {
                    // well, I'm no magician
                }
            }
        }

        if ($default === 'default') {
            // 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.
            $recipients[$default] = empty($recipients) ? _m('No subscriptions') : _m('Select recipient:');
        }

        asort($recipients);

        // TRANS: Dropdown label in direct notice form.
        $this->out->dropdown('to-box',
                             _m('To'),
                             $recipients,
                             null,
                             false,
                             $default);

        $this->out->element('textarea',
                            ['class' => 'notice_data-text',
                             'cols'  => 35,
                             'rows'  => 4,
                             'name'  => 'content'],
                             $this->content);

        $contentLimit = MessageModel::maxContent();

        if ($contentLimit > 0) {
            $this->out->element('span',
                                ['class' => 'count'],
                                $contentLimit);
        }
    }

    /**
     * Action elements.
     *
     * @return void
     */
    function formActions()
    {
        $this->out->element('input',
                            ['id'    => 'notice_action-submit',
                             'class' => 'submit',
                             'name'  => 'message_send',
                             'type'  => 'submit',
                             // TRANS: Button text for sending a direct notice.
                             'value' => _m('Send button for direct notice', 'Send')]);
    }

    /**
     * Show the form.
     *
     * @return void
     */
    function show()
    {
        $this->elementStart('div', 'input_forms');
        $this->elementStart('div',
                            ['id'    => 'input_form_direct',
                             'class' => 'input_form current nonav']);

        parent::show();

        $this->elementEnd('div');
        $this->elementEnd('div');
    }
}


code:
<?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);
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * GNUsocial implementation of Direct Messages
 *
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

defined('GNUSOCIAL') || die();

/**
 * A single item in a message list
 *
 * @category  Plugin
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
abstract class MessageListItem extends Widget
{
    protected $message;

    /**
     * Constructor.
     *
     * @param HTMLOutputter $out     Output context
     * @param Notice        $message Message to show
     */
    function __construct(HTMLOutputter $out, $message)
    {
        parent::__construct($out);
        $this->message = $message;
    }

    /**
     * Show the widget.
     *
     * @return void
     */
    function show()
    {
        $profile = $this->getMessageProfile();
        if (is_null($profile)) {
            // null most probably because there are no attention profiles and
            // the UI below isn't ready for that, yet.
            return;
        }

        $this->out->elementStart('li', ['class' => 'h-entry notice',
                                        'id'    => 'message-' . $this->message->getID()]);

        $this->out->elementStart('a', ['href'  => $profile->getUrl(),
                                       'class' => 'p-author']);
        $avatarUrl = $profile->avatarUrl(AVATAR_STREAM_SIZE);
        $this->out->element('img', ['src'    => $avatarUrl,
                                    'class'  => 'avatar u-photo',
                                    'width'  => AVATAR_STREAM_SIZE,
                                    'height' => AVATAR_STREAM_SIZE,
                                    'alt'    => $profile->getBestName()]);
        $this->out->element('span', ['class' => 'nickname fn'], $profile->getNickname());
        $this->out->elementEnd('a');

        // FIXME: URL, image, video, audio
        $this->out->elementStart('div', ['class' => 'e-content']);
        $this->out->raw($this->message->getRendered());
        $this->out->elementEnd('div');

        $messageurl = common_local_url('showmessage',
                                       ['message' => $this->message->getID()]);

        $this->out->elementStart('div', 'entry-metadata');
        $this->out->elementStart('a', ['rel'   => 'bookmark',
                                       'class' => 'timestamp',
                                       'href'  => $messageurl]);
        $dt = common_date_iso8601($this->message->getCreated());
        $this->out->element('time',
                            ['class'    => 'dt-published',
                             'datetime' => common_date_iso8601($this->message->getCreated()),
                             // TRANS: Timestamp title (tooltip text) for NoticeListItem
                             'title'    => common_exact_date($this->message->getCreated())],
                            common_date_string($this->message->getCreated()));
        $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 = [
            // 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(string $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',
                                    ['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(): ?Profile;
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * GNUsocial implementation of Direct Messages
 *
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */

defined('GNUSOCIAL') || die();

/**
 * Model for a direct message
 *
 * @category  Plugin
 * @package   GNUsocial
 * @author    Bruno Casteleiro <brunoccast@fc.up.pt>
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 */
class MessageModel
{
    /**
     * Retrieve size-limit for messages content
     *
     * @return int size-limit
     */
    public static function maxContent(): int
    {
        $desclimit = common_config('message', 'contentlimit');
        // null => use global limit (distinct from 0!)
        if (is_null($desclimit) || !is_int($desclimit)) {
            $desclimit = common_config('site', 'textlimit');
        }
        return $desclimit;
    }

    /**
     * Is message-text too long?
     *
     * @param string $content message-text
     * @return bool true if too long, false otherwise
     */
    public static function contentTooLong(string $content): bool
    {
        $contentlimit = self::maxContent();
        return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit));
    }

    /**
     * Return data object of messages received by some user.
     *
     * @param User $to receiver
     * @param int|null $page page limiter
     * @return Notice data object with stream for messages
     */
    public static function inboxMessages(User $to, ?int $page = null)
    {
        $attention = new Attention();
        $attention->selectAdd('notice_id');
        $attention->whereAdd('profile_id = ' . $to->getID());

        $ids = $attention->find() ? $attention->fetchAll('notice_id') : [];

        $reply = new Reply();
        $reply->selectAdd('notice_id');
        $reply->whereAdd('profile_id = ' . $to->getID());

        if ($reply->find()) {
            $ids = array_unique(
                array_merge($ids, $reply->fetchAll('notice_id'))
            );
        } else if (empty($ids)) {
            return null;
        }

        $message = new Notice();

        $message->whereAdd('scope = ' . NOTICE::MESSAGE_SCOPE);
        $message->whereAddIn('id', $ids, 'int');
        $message->orderBy('created DESC, id DESC');

        if (!is_null($page) && $page >= 0) {
            $page = ($page == 0) ? 1 : $page;
            $message->limit(($page - 1) * MESSAGES_PER_PAGE,
                        MESSAGES_PER_PAGE + 1);
        }

        return $message->find() ? $message : null;
    }

    /**
     * Return data object of messages sent by some user.
     *
     * @param User $from sender
     * @param int|null $page page limiter
     * @return Notice data object with stream for messages
     */
    public static function outboxMessages(User $from, ?int $page = null)
    {
        $message = new Notice();

        $message->profile_id = $from->getID();
        $message->whereAdd('scope = ' . NOTICE::MESSAGE_SCOPE);
        $message->orderBy('created DESC, id DESC');

        if (!is_null($page) && $page >= 0) {
            $page = ($page == 0) ? 1 : $page;
            $message->limit(($page - 1) * MESSAGES_PER_PAGE,
                        MESSAGES_PER_PAGE + 1);
        }

        return $message->find() ? $message : null;
    }

    /**
     * Save a new message.
     *
     * @param Profile $from sender
     * @param string $content message-text
     * @param string $source message's source
     * @return Notice stored message
     */
    public static function saveNew(Profile $from, string $content, string $source = 'web'): Notice
    {
        return Notice::saveNew($from->getID(),
                               $content,
                               $source,
                               ['distribute' => false, // using events to handle remote distribution
                                'scope'      => NOTICE::MESSAGE_SCOPE]);
    }
}


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-21 10:51+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"

#. TRANS: Menu item in personal group navigation menu.
#: DirectMessagePlugin.php:134
msgctxt "MENU"
msgid "Messages"
msgstr ""

#. TRANS: Link text for link on user profile.
#: DirectMessagePlugin.php:167
msgctxt "BUTTON"
msgid "Message"
msgstr ""

#. TRANS: Plugin description.
#: DirectMessagePlugin.php:223
msgid "Direct Message to other local users."
msgstr ""

#. TRANS: Form legend for direct notice.
#: lib/messageform.php:99
msgid "Send a direct notice"
msgstr ""

#. 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.
#: lib/messageform.php:157
msgid "No subscriptions"
msgstr ""

#: lib/messageform.php:157
msgid "Select recipient:"
msgstr ""

#: lib/messageform.php:164
msgid "To"
msgstr ""

#. TRANS: Button text for sending a direct notice.
#: lib/messageform.php:199
msgctxt "Send button for direct notice"
msgid "Send"
msgstr ""

#. TRANS: Menu item in mailbox menu. Leads to incoming private messages.
#: lib/mailboxmenu.php:59
msgctxt "MENU"
msgid "Inbox"
msgstr ""

#. TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
#: lib/mailboxmenu.php:66
msgctxt "MENU"
msgid "Outbox"
msgstr ""

#. 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.
#: lib/messagecommand.php:43
#, php-format
msgid "Message too long - maximum is %1$d character, you sent %2$d."
msgid_plural "Message too long - maximum is %1$d characters, you sent %2$d."
msgstr[0] ""
msgstr[1] ""

#. TRANS: A possible notice source (web interface).
#: lib/messagelistitem.php:127
msgctxt "SOURCE"
msgid "web"
msgstr ""

#. TRANS: A possible notice source (XMPP).
#: lib/messagelistitem.php:129
msgctxt "SOURCE"
msgid "xmpp"
msgstr ""

#. TRANS: A possible notice source (e-mail).
#: lib/messagelistitem.php:131
msgctxt "SOURCE"
msgid "mail"
msgstr ""

#. TRANS: A possible notice source (OpenMicroBlogging).
#: lib/messagelistitem.php:133
msgctxt "SOURCE"
msgid "omb"
msgstr ""

#. TRANS: A possible notice source (Application Programming Interface).
#: lib/messagelistitem.php:135
msgctxt "SOURCE"
msgid "api"
msgstr ""

#. TRANS: Title for outbox for any but the fist page.
#. TRANS: %1$s is the user nickname, %2$d is the page number.
#: actions/outbox.php:50
#, php-format
msgid "Outbox for %1$s - page %2$d"
msgstr ""

#. TRANS: Title for first page of outbox.
#: actions/outbox.php:54
#, php-format
msgid "Outbox for %s"
msgstr ""

#. TRANS: Instructions for outbox.
#: actions/outbox.php:84
msgid "This is your outbox, which lists private messages you have sent."
msgstr ""

#. TRANS: Client error displayed requesting a single message that does not exist.
#: actions/showmessage.php:63
msgid "No such message."
msgstr ""

#. TRANS: Client error displayed requesting a single direct message the requesting user was not a party in.
#: actions/showmessage.php:83
msgid "Only the sender and recipients may read this message."
msgstr ""

#: actions/showmessage.php:109
#, php-format
msgid "Message to many on %1$s"
msgstr ""

#. 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.
#: actions/showmessage.php:115
#, php-format
msgid "Message to %1$s on %2$s"
msgstr ""

#. TRANS: Page title for single message display.
#. TRANS: %1$s is the sending user's nickname, $2$s is a timestamp.
#: actions/showmessage.php:123
#, php-format
msgid "Message from %1$s on %2$s"
msgstr ""

#. TRANS: Form validation error displayed when message content is too long.
#. TRANS: %d is the maximum number of characters for a message.
#: actions/apidirectmessagenew.php:104 actions/newmessage.php:99
#, php-format
msgid "That's too long. Maximum message size is %d character."
msgid_plural "That's too long. Maximum message size is %d characters."
msgstr[0] ""
msgstr[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.
#: actions/inbox.php:50
#, php-format
msgid "Inbox for %1$s - page %2$d"
msgstr ""

#. TRANS: Title for the first page of the inbox page.
#. TRANS: %s is the user's nickname.
#: actions/inbox.php:55
#, php-format
msgid "Inbox for %s"
msgstr ""

#. TRANS: Instructions for user inbox page.
#: actions/inbox.php:85
msgid "This is your inbox, which lists your incoming private messages."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-06 16:07+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Afrikaans (http://www.transifex.com/gnu-social/gnu-social/language/af/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: af\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Menu item in personal group navigation menu.
#: DirectMessagePlugin.php:122
msgctxt "MENU"
msgid "Messages"
msgstr ""

#. TRANS: Link text for link on user profile.
#: DirectMessagePlugin.php:142
msgctxt "BUTTON"
msgid "Message"
msgstr ""

#. TRANS: Plugin description.
#: DirectMessagePlugin.php:168
msgid "Direct Message to other local users (broken out of core)."
msgstr ""

#. TRANS: Form validation error displayed when message content is too long.
#. TRANS: %d is the maximum number of characters for a message.
#: actions/apidirectmessagenew.php:106 actions/newmessage.php:123
#, php-format
msgid "That's too long. Maximum message size is %d character."
msgid_plural "That's too long. Maximum message size is %d characters."
msgstr[0] ""
msgstr[1] ""

#. TRANS: Menu item in mailbox menu. Leads to incoming private messages.
#: lib/mailboxmenu.php:59
msgctxt "MENU"
msgid "Inbox"
msgstr ""

#. TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
#: lib/mailboxmenu.php:66
msgctxt "MENU"
msgid "Outbox"
msgstr ""

#. 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.
#: lib/messagecommand.php:43
#, php-format
msgid "Message too long - maximum is %1$d character, you sent %2$d."
msgid_plural "Message too long - maximum is %1$d characters, you sent %2$d."
msgstr[0] ""
msgstr[1] ""

#. TRANS: Button text for sending a direct notice.
#: lib/messageform.php:175
msgctxt "Send button for sending notice"
msgid "Send"
msgstr "Stuur"

#. TRANS: A possible notice source (web interface).
#: lib/messagelistitem.php:137
msgctxt "SOURCE"
msgid "web"
msgstr ""

#. TRANS: A possible notice source (XMPP).
#: lib/messagelistitem.php:139
msgctxt "SOURCE"
msgid "xmpp"
msgstr ""

#. TRANS: A possible notice source (e-mail).
#: lib/messagelistitem.php:141
msgctxt "SOURCE"
msgid "mail"
msgstr ""

#. TRANS: A possible notice source (OpenMicroBlogging).
#: lib/messagelistitem.php:143
msgctxt "SOURCE"
msgid "omb"
msgstr ""

#. TRANS: A possible notice source (Application Programming Interface).
#: lib/messagelistitem.php:145
msgctxt "SOURCE"
msgid "api"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-06 16:07+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Arabic (http://www.transifex.com/gnu-social/gnu-social/language/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"

#. TRANS: Menu item in personal group navigation menu.
#: DirectMessagePlugin.php:122
msgctxt "MENU"
msgid "Messages"
msgstr ""

#. TRANS: Link text for link on user profile.
#: DirectMessagePlugin.php:142
msgctxt "BUTTON"
msgid "Message"
msgstr "راسل"

#. TRANS: Plugin description.
#: DirectMessagePlugin.php:168
msgid "Direct Message to other local users (broken out of core)."
msgstr ""

#. TRANS: Form validation error displayed when message content is too long.
#. TRANS: %d is the maximum number of characters for a message.
#: actions/apidirectmessagenew.php:106 actions/newmessage.php:123
#, php-format
msgid "That's too long. Maximum message size is %d character."
msgid_plural "That's too long. Maximum message size is %d characters."
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
msgstr[5] "هذا أطول من الحد المسموح به. لا يسمح بوضع أكثر من %d حرف في الرسالة."

#. TRANS: Menu item in mailbox menu. Leads to incoming private messages.
#: lib/mailboxmenu.php:59
msgctxt "MENU"
msgid "Inbox"
msgstr "صندوق الوارد"

#. TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
#: lib/mailboxmenu.php:66
msgctxt "MENU"
msgid "Outbox"
msgstr ""

#. 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.
#: lib/messagecommand.php:43
#, php-format
msgid "Message too long - maximum is %1$d character, you sent %2$d."
msgid_plural "Message too long - maximum is %1$d characters, you sent %2$d."
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
msgstr[5] ""

#. TRANS: Button text for sending a direct notice.
#: lib/messageform.php:175
msgctxt "Send button for sending notice"
msgid "Send"
msgstr "أرسل"

#. TRANS: A possible notice source (web interface).
#: lib/messagelistitem.php:137
msgctxt "SOURCE"
msgid "web"
msgstr "الوب"

#. TRANS: A possible notice source (XMPP).
#: lib/messagelistitem.php:139
msgctxt "SOURCE"
msgid "xmpp"
msgstr ""

#. TRANS: A possible notice source (e-mail).
#: lib/messagelistitem.php:141
msgctxt "SOURCE"
msgid "mail"
msgstr ""

#. TRANS: A possible notice source (OpenMicroBlogging).
#: lib/messagelistitem.php:143
msgctxt "SOURCE"
msgid "omb"
msgstr ""

#. TRANS: A possible notice source (Application Programming Interface).
#: lib/messagelistitem.php:145
msgctxt "SOURCE"
msgid "api"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-06 16:07+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Arabic (Egypt) (http://www.transifex.com/gnu-social/gnu-social/language/ar_EG/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar_EG\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"

#. TRANS: Menu item in personal group navigation menu.
#: DirectMessagePlugin.php:122
msgctxt "MENU"
msgid "Messages"
msgstr ""

#. TRANS: Link text for link on user profile.
#: DirectMessagePlugin.php:142
msgctxt "BUTTON"
msgid "Message"
msgstr ""

#. TRANS: Plugin description.
#: DirectMessagePlugin.php:168
msgid "Direct Message to other local users (broken out of core)."
msgstr ""

#. TRANS: Form validation error displayed when message content is too long.
#. TRANS: %d is the maximum number of characters for a message.
#: actions/apidirectmessagenew.php:106 actions/newmessage.php:123
#, php-format
msgid "That's too long. Maximum message size is %d character."
msgid_plural "That's too long. Maximum message size is %d characters."
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
msgstr[5] ""

#. TRANS: Menu item in mailbox menu. Leads to incoming private messages.
#: lib/mailboxmenu.php:59
msgctxt "MENU"
msgid "Inbox"
msgstr ""

#. TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
#: lib/mailboxmenu.php:66
msgctxt "MENU"
msgid "Outbox"
msgstr ""

#. 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.
#: lib/messagecommand.php:43
#, php-format
msgid "Message too long - maximum is %1$d character, you sent %2$d."
msgid_plural "Message too long - maximum is %1$d characters, you sent %2$d."
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
msgstr[5] ""

#. TRANS: Button text for sending a direct notice.
#: lib/messageform.php:175
msgctxt "Send button for sending notice"
msgid "Send"
msgstr ""

#. TRANS: A possible notice source (web interface).
#: lib/messagelistitem.php:137
msgctxt "SOURCE"
msgid "web"
msgstr ""

#. TRANS: A possible notice source (XMPP).
#: lib/messagelistitem.php:139
msgctxt "SOURCE"
msgid "xmpp"
msgstr ""

#. TRANS: A possible notice source (e-mail).
#: lib/messagelistitem.php:141
msgctxt "SOURCE"
msgid "mail"
msgstr ""

#. TRANS: A possible notice source (OpenMicroBlogging).
#: lib/messagelistitem.php:143
msgctxt "SOURCE"
msgid "omb"
msgstr ""

#. TRANS: A possible notice source (Application Programming Interface).
#: lib/messagelistitem.php:145
msgctxt "SOURCE"
msgid "api"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-06 16:07+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Asturian (http://www.transifex.com/gnu-social/gnu-social/language/ast/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ast\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Menu item in personal group navigation menu.
#: DirectMessagePlugin.php:122
msgctxt "MENU"
msgid "Messages"
msgstr ""

#. TRANS: Link text for link on user profile.
#: DirectMessagePlugin.php:142
msgctxt "BUTTON"
msgid "Message"
msgstr ""

#. TRANS: Plugin description.
#: DirectMessagePlugin.php:168
msgid "Direct Message to other local users (broken out of core)."
msgstr ""

#. TRANS: Form validation error displayed when message content is too long.
#. TRANS: %d is the maximum number of characters for a message.
#: actions/apidirectmessagenew.php:106 actions/newmessage.php:123
#, php-format
msgid "That's too long. Maximum message size is %d character."
msgid_plural "That's too long. Maximum message size is %d characters."
msgstr[0] ""
msgstr[1] ""

#. TRANS: Menu item in mailbox menu. Leads to incoming private messages.
#: lib/mailboxmenu.php:59
msgctxt "MENU"
msgid "Inbox"
msgstr ""

#. TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
#: lib/mailboxmenu.php:66
msgctxt "MENU"
msgid "Outbox"
msgstr ""

#. 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.
#: lib/messagecommand.php:43
#, php-format
msgid "Message too long - maximum is %1$d character, you sent %2$d."
msgid_plural "Message too long - maximum is %1$d characters, you sent %2$d."
msgstr[0] ""
msgstr[1] ""

#. TRANS: Button text for sending a direct notice.
#: lib/messageform.php:175
msgctxt "Send button for sending notice"
msgid "Send"
msgstr ""

#. TRANS: A possible notice source (web interface).
#: lib/messagelistitem.php:137
msgctxt "SOURCE"
msgid "web"
msgstr ""

#. TRANS: A possible notice source (XMPP).
#: lib/messagelistitem.php:139
msgctxt "SOURCE"
msgid "xmpp"
msgstr ""

#. TRANS: A possible notice source (e-mail).
#: lib/messagelistitem.php:141
msgctxt "SOURCE"
msgid "mail"
msgstr ""

#. TRANS: A possible notice source (OpenMicroBlogging).
#: lib/messagelistitem.php:143
msgctxt "SOURCE"
msgid "omb"
msgstr ""

#. TRANS: A possible notice source (Application Programming Interface).
#: lib/messagelistitem.php:145
msgctxt "SOURCE"
msgid "api"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-06 16:07+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Belarusian (Tarask) (http://www.transifex.com/gnu-social/gnu-social/language/be@tarask/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: be@tarask\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"

#. TRANS: Menu item in personal group navigation menu.
#: DirectMessagePlugin.php:122
msgctxt "MENU"
msgid "Messages"
msgstr ""

#. TRANS: Link text for link on user profile.
#: DirectMessagePlugin.php:142
msgctxt "BUTTON"
msgid "Message"
msgstr ""

#. TRANS: Plugin description.
#: DirectMessagePlugin.php:168
msgid "Direct Message to other local users (broken out of core)."
msgstr ""

#. TRANS: Form validation error displayed when message content is too long.
#. TRANS: %d is the maximum number of characters for a message.
#: actions/apidirectmessagenew.php:106 actions/newmessage.php:123
#, php-format
msgid "That's too long. Maximum message size is %d character."
msgid_plural "That's too long. Maximum message size is %d characters."
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgstr[3] ""

#. TRANS: Menu item in mailbox menu. Leads to incoming private messages.
#: lib/mailboxmenu.php:59
msgctxt "MENU"
msgid "Inbox"
msgstr ""

#. TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
#: lib/mailboxmenu.php:66
msgctxt "MENU"
msgid "Outbox"
msgstr ""

#. 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.
#: lib/messagecommand.php:43
#, php-format
msgid "Message too long - maximum is %1$d character, you sent %2$d."
msgid_plural "Message too long - maximum is %1$d characters, you sent %2$d."
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgstr[3] ""

#. TRANS: Button text for sending a direct notice.
#: lib/messageform.php:175
msgctxt "Send button for sending notice"
msgid "Send"
msgstr "Даслаць"

#. TRANS: A possible notice source (web interface).
#: lib/messagelistitem.php:137
msgctxt "SOURCE"
msgid "web"
msgstr ""

#. TRANS: A possible notice source (XMPP).
#: lib/messagelistitem.php:139
msgctxt "SOURCE"
msgid "xmpp"
msgstr ""

#. TRANS: A possible notice source (e-mail).
#: lib/messagelistitem.php:141
msgctxt "SOURCE"
msgid "mail"
msgstr ""

#. TRANS: A possible notice source (OpenMicroBlogging).
#: lib/messagelistitem.php:143
msgctxt "SOURCE"
msgid "omb"
msgstr ""

#. TRANS: A possible notice source (Application Programming Interface).
#: lib/messagelistitem.php:145
msgctxt "SOURCE"
msgid "api"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-06 16:07+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Bulgarian (http://www.transifex.com/gnu-social/gnu-social/language/bg/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: bg\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Menu item in personal group navigation menu.
#: DirectMessagePlugin.php:122
msgctxt "MENU"
msgid "Messages"
msgstr ""

#. TRANS: Link text for link on user profile.
#: DirectMessagePlugin.php:142
msgctxt "BUTTON"
msgid "Message"
msgstr ""

#. TRANS: Plugin description.
#: DirectMessagePlugin.php:168
msgid "Direct Message to other local users (broken out of core)."
msgstr ""

#. TRANS: Form validation error displayed when message content is too long.
#. TRANS: %d is the maximum number of characters for a message.
#: actions/apidirectmessagenew.php:106 actions/newmessage.php:123
#, php-format
msgid "That's too long. Maximum message size is %d character."
msgid_plural "That's too long. Maximum message size is %d characters."
msgstr[0] ""
msgstr[1] ""

#. TRANS: Menu item in mailbox menu. Leads to incoming private messages.
#: lib/mailboxmenu.php:59
msgctxt "MENU"
msgid "Inbox"
msgstr ""

#. TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
#: lib/mailboxmenu.php:66
msgctxt "MENU"
msgid "Outbox"
msgstr ""

#. 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.
#: lib/messagecommand.php:43
#, php-format
msgid "Message too long - maximum is %1$d character, you sent %2$d."
msgid_plural "Message too long - maximum is %1$d characters, you sent %2$d."
msgstr[0] ""
msgstr[1] ""

#. TRANS: Button text for sending a direct notice.
#: lib/messageform.php:175
msgctxt "Send button for sending notice"
msgid "Send"
msgstr ""

#. TRANS: A possible notice source (web interface).
#: lib/messagelistitem.php:137
msgctxt "SOURCE"
msgid "web"
msgstr ""

#. TRANS: A possible notice source (XMPP).
#: lib/messagelistitem.php:139
msgctxt "SOURCE"
msgid "xmpp"
msgstr ""

#. TRANS: A possible notice source (e-mail).
#: lib/messagelistitem.php:141
msgctxt "SOURCE"
msgid "mail"
msgstr ""

#. TRANS: A possible notice source (OpenMicroBlogging).
#: lib/messagelistitem.php:143
msgctxt "SOURCE"
msgid "omb"
msgstr ""

#. TRANS: A possible notice source (Application Programming Interface).
#: lib/messagelistitem.php:145
msgctxt "SOURCE"
msgid "api"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-06 16:07+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Bengali (India) (http://www.transifex.com/gnu-social/gnu-social/language/bn_IN/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: bn_IN\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Menu item in personal group navigation menu.
#: DirectMessagePlugin.php:122
msgctxt "MENU"
msgid "Messages"
msgstr ""

#. TRANS: Link text for link on user profile.
#: DirectMessagePlugin.php:142
msgctxt "BUTTON"
msgid "Message"
msgstr ""

#. TRANS: Plugin description.
#: DirectMessagePlugin.php:168
msgid "Direct Message to other local users (broken out of core)."
msgstr ""

#. TRANS: Form validation error displayed when message content is too long.
#. TRANS: %d is the maximum number of characters for a message.
#: actions/apidirectmessagenew.php:106 actions/newmessage.php:123
#, php-format
msgid "That's too long. Maximum message size is %d character."
msgid_plural "That's too long. Maximum message size is %d characters."
msgstr[0] ""
msgstr[1] ""

#. TRANS: Menu item in mailbox menu. Leads to incoming private messages.
#: lib/mailboxmenu.php:59
msgctxt "MENU"
msgid "Inbox"
msgstr ""

#. TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
#: lib/mailboxmenu.php:66
msgctxt "MENU"
msgid "Outbox"
msgstr ""

#. 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.
#: lib/messagecommand.php:43
#, php-format
msgid "Message too long - maximum is %1$d character, you sent %2$d."
msgid_plural "Message too long - maximum is %1$d characters, you sent %2$d."
msgstr[0] ""
msgstr[1] ""

#. TRANS: Button text for sending a direct notice.
#: lib/messageform.php:175
msgctxt "Send button for sending notice"
msgid "Send"
msgstr ""

#. TRANS: A possible notice source (web interface).
#: lib/messagelistitem.php:137
msgctxt "SOURCE"
msgid "web"
msgstr ""

#. TRANS: A possible notice source (XMPP).
#: lib/messagelistitem.php:139
msgctxt "SOURCE"
msgid "xmpp"
msgstr ""

#. TRANS: A possible notice source (e-mail).
#: lib/messagelistitem.php:141
msgctxt "SOURCE"
msgid "mail"
msgstr ""

#. TRANS: A possible notice source (OpenMicroBlogging).
#: lib/messagelistitem.php:143
msgctxt "SOURCE"
msgid "omb"
msgstr ""

#. TRANS: A possible notice source (Application Programming Interface).
#: lib/messagelistitem.php:145
msgctxt "SOURCE"
msgid "api"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-06 16:07+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Breton (http://www.transifex.com/gnu-social/gnu-social/language/br/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: br\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#. TRANS: Menu item in personal group navigation menu.
#: DirectMessagePlugin.php:122
msgctxt "MENU"
msgid "Messages"
msgstr ""

#. TRANS: Link text for link on user profile.
#: DirectMessagePlugin.php:142
msgctxt "BUTTON"
msgid "Message"
msgstr ""

#. TRANS: Plugin description.
#: DirectMessagePlugin.php:168
msgid "Direct Message to other local users (broken out of core)."
msgstr ""

#. TRANS: Form validation error displayed when message content is too long.
#. TRANS: %d is the maximum number of characters for a message.
#: actions/apidirectmessagenew.php:106 actions/newmessage.php:123
#, php-format
msgid "That's too long. Maximum message size is %d character."
msgid_plural "That's too long. Maximum message size is %d characters."
msgstr[0] ""
msgstr[1] "Re hir eo. %d eo an niver brasañ a arouezennoù a c'haller kaout en ur gemennadenn."

#. TRANS: Menu item in mailbox menu. Leads to incoming private messages.
#: lib/mailboxmenu.php:59
msgctxt "MENU"
msgid "Inbox"
msgstr ""

#. TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
#: lib/mailboxmenu.php:66
msgctxt "MENU"
msgid "Outbox"
msgstr ""

#. 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.
#: lib/messagecommand.php:43
#, php-format
msgid "Message too long - maximum is %1$d character, you sent %2$d."
msgid_plural "Message too long - maximum is %1$d characters, you sent %2$d."
msgstr[0] ""
msgstr[1] ""

#. TRANS: Button text for sending a direct notice.
#: lib/messageform.php:175
msgctxt "Send button for sending notice"
msgid "Send"
msgstr "Kas"

#. TRANS: A possible notice source (web interface).
#: lib/messagelistitem.php:137
msgctxt "SOURCE"
msgid "web"
msgstr ""

#. TRANS: A possible notice source (XMPP).
#: lib/messagelistitem.php:139
msgctxt "SOURCE"
msgid "xmpp"
msgstr ""

#. TRANS: A possible notice source (e-mail).
#: lib/messagelistitem.php:141
msgctxt "SOURCE"
msgid "mail"
msgstr ""

#. TRANS: A possible notice source (OpenMicroBlogging).
#: lib/messagelistitem.php:143
msgctxt "SOURCE"
msgid "omb"
msgstr ""

#. TRANS: A possible notice source (Application Programming Interface).
#: lib/messagelistitem.php:145
msgctxt "SOURCE"
msgid "api"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-06 16:07+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Catalan (http://www.transifex.com/gnu-social/gnu-social/language/ca/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ca\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Menu item in personal group navigation menu.
#: DirectMessagePlugin.php:122
msgctxt "MENU"
msgid "Messages"
msgstr ""

#. TRANS: Link text for link on user profile.
#: DirectMessagePlugin.php:142
msgctxt "BUTTON"
msgid "Message"
msgstr "Missatge"

#. TRANS: Plugin description.
#: DirectMessagePlugin.php:168
msgid "Direct Message to other local users (broken out of core)."
msgstr ""

#. TRANS: Form validation error displayed when message content is too long.
#. TRANS: %d is the maximum number of characters for a message.
#: actions/apidirectmessagenew.php:106 actions/newmessage.php:123
#, php-format
msgid "That's too long. Maximum message size is %d character."
msgid_plural "That's too long. Maximum message size is %d characters."
msgstr[0] ""
msgstr[1] "És massa llarg. La mida màxima del missatge és %d caràcters."

#. TRANS: Menu item in mailbox menu. Leads to incoming private messages.
#: lib/mailboxmenu.php:59
msgctxt "MENU"
msgid "Inbox"
msgstr "Safata d'entrada"

#. TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
#: lib/mailboxmenu.php:66
msgctxt "MENU"
msgid "Outbox"
msgstr ""

#. 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.
#: lib/messagecommand.php:43
#, php-format
msgid "Message too long - maximum is %1$d character, you sent %2$d."
msgid_plural "Message too long - maximum is %1$d characters, you sent %2$d."
msgstr[0] ""
msgstr[1] ""

#. TRANS: Button text for sending a direct notice.
#: lib/messageform.php:175
msgctxt "Send button for sending notice"
msgid "Send"
msgstr "Envia"

#. TRANS: A possible notice source (web interface).
#: lib/messagelistitem.php:137
msgctxt "SOURCE"
msgid "web"
msgstr "web"

#. TRANS: A possible notice source (XMPP).
#: lib/messagelistitem.php:139
msgctxt "SOURCE"
msgid "xmpp"
msgstr ""

#. TRANS: A possible notice source (e-mail).
#: lib/messagelistitem.php:141
msgctxt "SOURCE"
msgid "mail"
msgstr ""

#. TRANS: A possible notice source (OpenMicroBlogging).
#: lib/messagelistitem.php:143
msgctxt "SOURCE"
msgid "omb"
msgstr ""

#. TRANS: A possible notice source (Application Programming Interface).
#: lib/messagelistitem.php:145
msgctxt "SOURCE"
msgid "api"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-06 16:07+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Czech (http://www.transifex.com/gnu-social/gnu-social/language/cs/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: cs\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"

#. TRANS: Menu item in personal group navigation menu.
#: DirectMessagePlugin.php:122
msgctxt "MENU"
msgid "Messages"
msgstr ""

#. TRANS: Link text for link on user profile.
#: DirectMessagePlugin.php:142
msgctxt "BUTTON"
msgid "Message"
msgstr ""

#. TRANS: Plugin description.
#: DirectMessagePlugin.php:168
msgid "Direct Message to other local users (broken out of core)."
msgstr ""

#. TRANS: Form validation error displayed when message content is too long.
#. TRANS: %d is the maximum number of characters for a message.
#: actions/apidirectmessagenew.php:106 actions/newmessage.php:123
#, php-format
msgid "That's too long. Maximum message size is %d character."
msgid_plural "That's too long. Maximum message size is %d characters."
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""

#. TRANS: Menu item in mailbox menu. Leads to incoming private messages.
#: lib/mailboxmenu.php:59
msgctxt "MENU"
msgid "Inbox"
msgstr ""

#. TRANS: Menu item in mailbox menu. Leads to outgoing private messages.
#: lib/mailboxmenu.php:66
msgctxt "MENU"
msgid "Outbox"
msgstr ""

#. 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.
#: lib/messagecommand.php:43
#, php-format
msgid "Message too long - maximum is %1$d character, you sent %2$d."
msgid_plural "Message too long - maximum is %1$d characters, you sent %2$d."
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""

#. TRANS: Button text for sending a direct notice.
#: lib/messageform.php:175
msgctxt "Send button for sending notice"
msgid "Send"
msgstr "Odeslat"

#. TRANS: A possible notice source (web interface).
#: lib/messagelistitem.php:137
msgctxt "SOURCE"
msgid "web"
msgstr "webu"

#. TRANS: A possible notice source (XMPP).
#: lib/messagelistitem.php:139
msgctxt "SOURCE"
msgid "xmpp"
msgstr ""

#. TRANS: A possible notice source (e-mail).
#: lib/messagelistitem.php:141
msgctxt "SOURCE"
msgid "mail"
msgstr ""

#. TRANS: A possible notice source (OpenMicroBlogging).
#: lib/messagelistitem.php:143
msgctxt "SOURCE"
msgid "omb"
msgstr ""

#. TRANS: A possible notice source (Application Programming Interface).
#: lib/messagelistitem.php:145
msgctxt "SOURCE"
msgid "api"
msgstr ""