From 073ec99c54ad66e42dea1af62bab646aa9e48564 Mon Sep 17 00:00:00 2001
From: Evan Prodromou <evan@prodromou.name>
Date: Mon, 22 Dec 2008 14:50:41 -0500
Subject: [PATCH] bring mailbox.php into line with PEAR Coding Standards
 (mostly)

darcs-hash:20081222195041-84dde-3cc82f6b0f3e4e753c9525aa9a881cfb0c25830c.gz
---
 _darcs/inventory                              |   4 +-
 ...cc82f6b0f3e4e753c9525aa9a881cfb0c25830c.gz | Bin 0 -> 2729 bytes
 _darcs/pristine/lib/mailbox.php               | 402 ++++++++-----
 _darcs/tentative_pristine                     | 540 ++++++++++++------
 lib/mailbox.php                               | 402 ++++++++-----
 5 files changed, 867 insertions(+), 481 deletions(-)
 create mode 100644 _darcs/patches/20081222195041-84dde-3cc82f6b0f3e4e753c9525aa9a881cfb0c25830c.gz

diff --git a/_darcs/inventory b/_darcs/inventory
index b3f0045032..7f21ac58a1 100644
--- a/_darcs/inventory
+++ b/_darcs/inventory
@@ -33,4 +33,6 @@ Evan Prodromou <evan@prodromou.name>**20081221005837]
 [reformat lib/jabber.php for phpcs, including doc comments
 Evan Prodromou <evan@prodromou.name>**20081222173249] 
 [reformat lib/language.php for PEAR Coding Standards
-Evan Prodromou <evan@prodromou.name>**20081222193029] 
\ No newline at end of file
+Evan Prodromou <evan@prodromou.name>**20081222193029] 
+[bring mailbox.php into line with PEAR Coding Standards (mostly)
+Evan Prodromou <evan@prodromou.name>**20081222195041] 
\ No newline at end of file
diff --git a/_darcs/patches/20081222195041-84dde-3cc82f6b0f3e4e753c9525aa9a881cfb0c25830c.gz b/_darcs/patches/20081222195041-84dde-3cc82f6b0f3e4e753c9525aa9a881cfb0c25830c.gz
new file mode 100644
index 0000000000000000000000000000000000000000..502586ee8b10e3fc54286289790c3e11c6387ce6
GIT binary patch
literal 2729
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

literal 0
HcmV?d00001

diff --git a/_darcs/pristine/lib/mailbox.php b/_darcs/pristine/lib/mailbox.php
index 4ed8d17582..9039c5fdaa 100644
--- a/_darcs/pristine/lib/mailbox.php
+++ b/_darcs/pristine/lib/mailbox.php
@@ -1,9 +1,12 @@
 <?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
+/**
+ * Laconica, the distributed open-source microblogging tool
  *
- * This program is free software: you can redistribute it and/or modify
+ * 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.
@@ -15,158 +18,253 @@
  *
  * 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  Action
+ * @package   Laconica
+ * @author    Evan Prodromou <evan@controlyourself.ca>
+ * @copyright 2008 Control Yourself, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://laconi.ca/
  */
 
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('LACONICA')) {
+    exit(1);
+}
 
-require_once(INSTALLDIR.'/lib/personal.php');
+require_once INSTALLDIR.'/lib/personal.php';
 
 define('MESSAGES_PER_PAGE', 20);
 
-class MailboxAction extends PersonalAction {
-	
-	function handle($args) {
-
-		parent::handle($args);
-
-		$nickname = common_canonical_nickname($this->arg('nickname'));
-		$user = User::staticGet('nickname', $nickname);
-
-		if (!$user) {
-			$this->client_error(_('No such user.'), 404);
-			return;
-		}
-
-		$cur = common_current_user();
-		
-		if (!$cur || $cur->id != $user->id) {
-			$this->client_error(_('Only the user can read their own mailboxes.'), 403);
-			return;
-		}
-		
-		$profile = $user->getProfile();
-
-		if (!$profile) {
-			$this->server_error(_('User has no profile.'));
-			return;
-		}
-
-		$page = $this->trimmed('page');
-		
-		if (!$page) {
-			$page = 1;
-		}
-		
-		$this->show_page($user, $page);
-	}
-
-	function get_title($user, $page) {
-		return '';
-	}
-
-	function get_instructions() {
-		return '';
-	}
-
-	function show_top() {
-
-		$cur = common_current_user();
-		
-		common_message_form(NULL, $cur, NULL);
-		
-		$this->views_menu();
-	}
-	
-	function show_page($user, $page) {
-
-		common_show_header($this->get_title($user, $page),
-						   NULL, NULL,
-						   array($this, 'show_top'));
-		
-		$this->show_box($user, $page);
-		
-		common_show_footer();
-	}
-	
-	function show_box($user, $page) {
-		
-		$message = $this->get_messages($user, $page);
-		
-		if ($message) {
-			
-			$cnt = 0;
-			common_element_start('ul', array('id' => 'messages'));
-		
-			while ($message->fetch() && $cnt <= MESSAGES_PER_PAGE) {
-				$cnt++;
-				
-				if ($cnt > MESSAGES_PER_PAGE) {
-					break;
-				}
-				
-				$this->show_message($message);
-			}
-
-			common_element_end('ul');
-			
-			common_pagination($page > 1, $cnt > MESSAGES_PER_PAGE,
-							  $page, $this->trimmed('action'),
-							  array('nickname' => $user->nickname));
-			
-			$message->free();
-			unset($message);
-		}
-	}
-
-	# returns the profile we want to show with the message
-	
-	function get_message_profile($message) {
-		return NULL;
-	}
-	
-	function show_message($message) {
-
-		common_element_start('li', array('class' => 'message_single',
-										  'id' => 'message-' . $message->id));
-
-		$profile = $this->get_message_profile($message);
-		
-		$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
-		common_element_start('a', array('href' => $profile->profileurl));
-		common_element('img', array('src' => ($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_STREAM_SIZE),
-									'class' => 'avatar stream',
-									'width' => AVATAR_STREAM_SIZE,
-									'height' => AVATAR_STREAM_SIZE,
-									'alt' =>
-									($profile->fullname) ? $profile->fullname :
-									$profile->nickname));
-		common_element_end('a');
-		common_element('a', array('href' => $profile->profileurl,
-								  'class' => 'nickname'),
-					   $profile->nickname);
-		# FIXME: URL, image, video, audio
-		common_element_start('p', array('class' => 'content'));
-		common_raw($message->rendered);
-		common_element_end('p');
-		
-		$messageurl = common_local_url('showmessage', array('message' => $message->id));
-		
-		# XXX: we need to figure this out better. Is this right?
-		if (strcmp($message->uri, $messageurl) != 0 && preg_match('/^http/', $message->uri)) {
-			$messageurl = $message->uri;
-		}
-		common_element_start('p', 'time');
-		common_element('a', array('class' => 'permalink',
-								  'href' => $messageurl,
-								  'title' => common_exact_date($message->created)),
-					   common_date_string($message->created));
-		if ($message->source) {
-			common_text(_(' from '));
-			$this->source_link($message->source);
-		}
-		
-		common_element_end('p');
-		
-		common_element_end('li');
-	}
+/**
+ * common superclass for direct messages inbox and outbox
+ *
+ * @category Action
+ * @package  Laconica
+ * @author   Evan Prodromou <evan@controlyourself.ca>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://laconi.ca/
+ * @see      InboxAction
+ * @see      OutboxAction
+ */
+
+class MailboxAction extends PersonalAction
+{
+    /**
+     * output page based on arguments
+     *
+     * @param array $args HTTP arguments (from $_REQUEST)
+     *
+     * @return void
+     */
+
+    function handle($args)
+    {
+        parent::handle($args);
+
+        $nickname = common_canonical_nickname($this->arg('nickname'));
+
+        $user = User::staticGet('nickname', $nickname);
+
+        if (!$user) {
+            $this->client_error(_('No such user.'), 404);
+            return;
+        }
+
+        $cur = common_current_user();
+
+        if (!$cur || $cur->id != $user->id) {
+            $this->client_error(_('Only the user can read their own mailboxes.'),
+                                403);
+            return;
+        }
+
+        $profile = $user->getProfile();
+
+        if (!$profile) {
+            $this->server_error(_('User has no profile.'));
+            return;
+        }
+
+        $page = $this->trimmed('page');
+
+        if (!$page) {
+            $page = 1;
+        }
+
+        $this->show_page($user, $page);
+    }
+
+    /**
+     * returns the title of the page
+     *
+     * @param User $user current user
+     * @param int  $page current page
+     *
+     * @return string localised title of the page
+     */
+
+    function get_title($user, $page)
+    {
+        return '';
+    }
+
+    /**
+     * instructions for using this page
+     *
+     * @return string localised instructions for using the page
+     */
+
+    function get_instructions()
+    {
+        return '';
+    }
+
+    /**
+     * do structured output for the "instructions" are of the page
+     *
+     * @return void
+     */
+
+    function show_top()
+    {
+        $cur = common_current_user();
+
+        common_message_form(null, $cur, null);
+
+        $this->views_menu();
+    }
+
+    /**
+     * show a full page of output
+     *
+     * @param User $user The current user
+     * @param int  $page The page the user is on
+     *
+     * @return void
+     */
+
+    function show_page($user, $page)
+    {
+        common_show_header($this->get_title($user, $page),
+                           null, null,
+                           array($this, 'show_top'));
+
+        $this->show_box($user, $page);
+
+        common_show_footer();
+    }
+
+    /**
+     * show the messages for a mailbox in list format
+     *
+     * Includes the pagination links (before, after).
+     *
+     * @param User $user The current user
+     * @param int  $page The page the user is on
+     *
+     * @return void
+     */
+
+    function show_box($user, $page)
+    {
+        $message = $this->get_messages($user, $page);
+
+        if ($message) {
+
+            $cnt = 0;
+            common_element_start('ul', array('id' => 'messages'));
+
+            while ($message->fetch() && $cnt <= MESSAGES_PER_PAGE) {
+                $cnt++;
+
+                if ($cnt > MESSAGES_PER_PAGE) {
+                    break;
+                }
+
+                $this->show_message($message);
+            }
+
+            common_element_end('ul');
+
+            common_pagination($page > 1, $cnt > MESSAGES_PER_PAGE,
+                              $page, $this->trimmed('action'),
+                              array('nickname' => $user->nickname));
+
+            $message->free();
+            unset($message);
+        }
+    }
+
+    /**
+     * returns the profile we want to show with the message
+     *
+     * For inboxes, we show the sender; for outboxes, the recipient.
+     *
+     * @param Message $message The message to get the profile for
+     *
+     * @return Profile The profile that matches the message
+     */
+
+    function get_message_profile($message)
+    {
+        return null;
+    }
+
+    /**
+     * show a single message in the list format
+     *
+     * @param Message $message the message to show
+     *
+     * @return void
+     */
+
+    function show_message($message)
+    {
+        common_element_start('li', array('class' => 'message_single',
+                                         'id' => 'message-' . $message->id));
+
+        $profile = $this->get_message_profile($message);
+
+        $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
+        common_element_start('a', array('href' => $profile->profileurl));
+        common_element('img', array('src' => ($avatar) ?
+                                    common_avatar_display_url($avatar) :
+                                    common_default_avatar(AVATAR_STREAM_SIZE),
+                                    'class' => 'avatar stream',
+                                    'width' => AVATAR_STREAM_SIZE,
+                                    'height' => AVATAR_STREAM_SIZE,
+                                    'alt' =>
+                                    ($profile->fullname) ? $profile->fullname :
+                                    $profile->nickname));
+        common_element_end('a');
+        common_element('a', array('href' => $profile->profileurl,
+                                  'class' => 'nickname'),
+                       $profile->nickname);
+        // FIXME: URL, image, video, audio
+        common_element_start('p', array('class' => 'content'));
+        common_raw($message->rendered);
+        common_element_end('p');
+
+        $messageurl = common_local_url('showmessage',
+                                       array('message' => $message->id));
+
+        // XXX: we need to figure this out better. Is this right?
+        if (strcmp($message->uri, $messageurl) != 0 &&
+            preg_match('/^http/', $message->uri)) {
+            $messageurl = $message->uri;
+        }
+        common_element_start('p', 'time');
+        common_element('a', array('class' => 'permalink',
+                                  'href' => $messageurl,
+                                  'title' => common_exact_date($message->created)),
+                       common_date_string($message->created));
+        if ($message->source) {
+            common_text(_(' from '));
+            $this->source_link($message->source);
+        }
+
+        common_element_end('p');
+
+        common_element_end('li');
+    }
 }
diff --git a/_darcs/tentative_pristine b/_darcs/tentative_pristine
index 9b17c08d16..dd4a35214c 100644
--- a/_darcs/tentative_pristine
+++ b/_darcs/tentative_pristine
@@ -1,205 +1,393 @@
-hunk ./lib/language.php 2
+hunk ./lib/mailbox.php 2
 -/*
 - * Laconica - a distributed open-source microblogging tool
 - * Copyright (C) 2008, Controlez-Vous, Inc.
 +/**
 + * Laconica, the distributed open-source microblogging tool
-hunk ./lib/language.php 5
+hunk ./lib/mailbox.php 5
 - * This program is free software: you can redistribute it and/or modify
-+ * utility functions for i18n
++ * common superclass for direct messages inbox and outbox
 + *
 + * PHP version 5
 + *
 + * LICENCE: This program is free software: you can redistribute it and/or modify
-hunk ./lib/language.php 21
+hunk ./lib/mailbox.php 21
 + *
-+ * @category I18n
-+ * @package  Laconica
-+ * @author   Matthew Gregg <matthew.gregg@gmail.com>
-+ * @author   Ciaran Gultnieks <ciaran@ciarang.com>
-+ * @author   Evan Prodromou <evan@controlyourself.ca>
-+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
-+ * @link     http://laconi.ca/
-hunk ./lib/language.php 31
++ * @category  Action
++ * @package   Laconica
++ * @author    Evan Prodromou <evan@controlyourself.ca>
++ * @copyright 2008 Control Yourself, Inc.
++ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
++ * @link      http://laconi.ca/
+hunk ./lib/mailbox.php 30
 -if (!defined('LACONICA')) { exit(1); }
 +if (!defined('LACONICA')) {
 +    exit(1);
 +}
-hunk ./lib/language.php 35
+hunk ./lib/mailbox.php 34
+-require_once(INSTALLDIR.'/lib/personal.php');
++require_once INSTALLDIR.'/lib/personal.php';
+hunk ./lib/mailbox.php 38
+-class MailboxAction extends PersonalAction {
+-	
+-	function handle($args) {
 +/**
-+ * Content negotiation for language codes
++ * common superclass for direct messages inbox and outbox
 + *
-+ * @param string $httplang HTTP Accept-Language header
-+ *
-+ * @return string language code for best language match
++ * @category Action
++ * @package  Laconica
++ * @author   Evan Prodromou <evan@controlyourself.ca>
++ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
++ * @link     http://laconi.ca/
++ * @see      InboxAction
++ * @see      OutboxAction
 + */
-hunk ./lib/language.php 43
-+function client_prefered_language($httplang)
++
++class MailboxAction extends PersonalAction
 +{
-+    $client_langs = array();
-hunk ./lib/language.php 47
--function client_prefered_language($httplang) {
--        $client_langs = array();
--        $all_languages = common_config('site','languages');
-+    $all_languages = common_config('site', 'languages');
-hunk ./lib/language.php 49
--        preg_match_all('"(((\S\S)-?(\S\S)?)(;q=([0-9.]+))?)\s*(,\s*|$)"',strtolower($httplang),$httplang);
--        for ($i = 0; $i < count($httplang); $i++) {
--             if(!empty($httplang[2][$i])) {
--                    #if no q default to 1.0
--                    $client_langs[$httplang[2][$i]] = ($httplang[6][$i]? (float) $httplang[6][$i] : 1.0);
--                }
--                if(!empty($httplang[3][$i]) && empty($client_langs[$httplang[3][$i]])) {
--                    #if a catchall default 0.01 lower
--                    $client_langs[$httplang[3][$i]] = ($httplang[6][$i]? (float) $httplang[6][$i]-0.01 : 0.99);
--                }
--            }
--            #sort in decending q
--            arsort($client_langs);
-+    preg_match_all('"(((\S\S)-?(\S\S)?)(;q=([0-9.]+))?)\s*(,\s*|$)"',
-+                   strtolower($httplang), $httplang);
-hunk ./lib/language.php 52
--            foreach ($client_langs as $lang => $q) {
--                if (isset($all_languages[$lang])) {
--                    return($all_languages[$lang]['lang']);
--                }
--            }
--            return FALSE;
--}
-+    for ($i = 0; $i < count($httplang); $i++) {
-+        if (!empty($httplang[2][$i])) {
-+            // if no q default to 1.0
-+            $client_langs[$httplang[2][$i]] =
-+              ($httplang[6][$i]? (float) $httplang[6][$i] : 1.0);
++    /**
++     * output page based on arguments
++     *
++     * @param array $args HTTP arguments (from $_REQUEST)
++     *
++     * @return void
++     */
++
++    function handle($args)
++    {
++        parent::handle($args);
++
++        $nickname = common_canonical_nickname($this->arg('nickname'));
++
++        $user = User::staticGet('nickname', $nickname);
++
++        if (!$user) {
++            $this->client_error(_('No such user.'), 404);
++            return;
 +        }
-+        if (!empty($httplang[3][$i]) && empty($client_langs[$httplang[3][$i]])) {
-+            // if a catchall default 0.01 lower
-+            $client_langs[$httplang[3][$i]] =
-+              ($httplang[6][$i]? (float) $httplang[6][$i]-0.01 : 0.99);
++
++        $cur = common_current_user();
++
++        if (!$cur || $cur->id != $user->id) {
++            $this->client_error(_('Only the user can read their own mailboxes.'),
++                                403);
++            return;
 +        }
++
++        $profile = $user->getProfile();
++
++        if (!$profile) {
++            $this->server_error(_('User has no profile.'));
++            return;
++        }
++
++        $page = $this->trimmed('page');
++
++        if (!$page) {
++            $page = 1;
++        }
++
++        $this->show_page($user, $page);
 +    }
-+    // sort in decending q
-+    arsort($client_langs);
-hunk ./lib/language.php 67
--function get_nice_language_list() {
--        $nice_lang = array();
--        $all_languages = common_config('site','languages');
--        foreach ($all_languages as $lang) {
--                $nice_lang = $nice_lang + array($lang['lang'] => $lang['name']);
-+    foreach ($client_langs as $lang => $q) {
-+        if (isset($all_languages[$lang])) {
-+            return($all_languages[$lang]['lang']);
-hunk ./lib/language.php 71
--        return $nice_lang;
++
++    /**
++     * returns the title of the page
++     *
++     * @param User $user current user
++     * @param int  $page current page
++     *
++     * @return string localised title of the page
++     */
++
++    function get_title($user, $page)
++    {
++        return '';
 +    }
-+    return false;
-hunk ./lib/language.php 75
--// Get a list of all languages that are enabled in the default config. This
--// should ONLY be called when setting up the default config in common.php.
--// Any other attempt to get a list of lanugages should instead call
--// common_config('site','languages')
--function get_all_languages() {
--	return array(
--		'en-us' => array('q' => 1, 'lang' => 'en_US', 'name' => 'English (US)', 'direction' => 'ltr'),
--		'en-nz' => array('q' => 1, 'lang' => 'en_NZ', 'name' => 'English (NZ)', 'direction' => 'ltr'),
--		'en-gb' => array('q' => 1, 'lang' => 'en_GB', 'name' => 'English (British)', 'direction' => 'ltr'),
--		'en'    => array('q' => 1, 'lang' => 'en',    'name' => 'English', 'direction' => 'ltr'),
--		'da'    => array('q' => 0.1, 'lang' => 'da_DK', 'name' => 'Danish', 'direction' => 'ltr'),
--		'nl'    => array('q' => 1, 'lang' => 'nl_NL', 'name' => 'Dutch', 'direction' => 'ltr'),
--		'eo'    => array('q' => 0.1, 'lang' => 'eo',    'name' => 'Esperanto', 'direction' => 'ltr'),
--		'fr-fr' => array('q' => 0.9, 'lang' => 'fr_FR', 'name' => 'French', 'direction' => 'ltr'),
--		'de'    => array('q' => 1, 'lang' => 'de_DE', 'name' => 'German', 'direction' => 'ltr'),
--		'it'    => array('q' => 1, 'lang' => 'it_IT', 'name' => 'Italian', 'direction' => 'ltr'),
--		'ko'    => array('q' => 0.1, 'lang' => 'ko',    'name' => 'Korean', 'direction' => 'ltr'),
--		'nb'    => array('q' => 1, 'lang' => 'nb_NO', 'name' => 'Norwegian (bokmal)', 'direction' => 'ltr'),
--		'pt'    => array('q' => 0.2, 'lang' => 'pt',    'name' => 'Portuguese', 'direction' => 'ltr'),
--		'pt-br' => array('q' => 1, 'lang' => 'pt_BR', 'name' => 'Portuguese Brazil', 'direction' => 'ltr'),
--#		'ru'    => array('q' => 0.1, 'lang' => 'ru_RU', 'name' => 'Russian', 'direction' => 'ltr'),
--		'es'    => array('q' => 1, 'lang' => 'es',    'name' => 'Spanish', 'direction' => 'ltr'),
--		'tr'    => array('q' => 1, 'lang' => 'tr_TR', 'name' => 'Turkish', 'direction' => 'ltr'),
--		'uk'    => array('q' => 1, 'lang' => 'uk_UA', 'name' => 'Ukrainian', 'direction' => 'ltr'),
--#		'lt'    => array('q' => 0.1, 'lang' => 'lt_LT', 'name' => 'Lithuanian', 'direction' => 'ltr'),
--#		'sv'    => array('q' => 1, 'lang' => 'sv_SE', 'name' => 'Swedish', 'direction' => 'ltr'),
--		'pl'	=> array('q' => 1, 'lang' => 'pl_PL', 'name' => 'Polish', 'direction' => 'ltr'),
--		'mk'	=> array('q' => 1, 'lang' => 'mk_MK', 'name' => 'Macedonian', 'direction' => 'ltr'),
--		'jp'	=> array('q' => 0.1, 'lang' => 'ja_JP', 'name' => 'Japanese', 'direction' => 'ltr'),
--		'cs'	=> array('q' => 1, 'lang' => 'cs_CZ', 'name' => 'Czech', 'direction' => 'ltr'),
--		'ca'	=> array('q' => 1, 'lang' => 'ca_ES', 'name' => 'Catalan', 'direction' => 'ltr'),
--#		'hr'    => array('q' => 0.1, 'lang' => 'he_IL', 'name' => 'Hebrew', 'direction' => 'ltr')
--	);
-+/**
-+ * returns a simple code -> name mapping for languages
-+ *
-+ * @return array map of available languages by code to language name.
-+ */
 +
-+function get_nice_language_list()
-+{
-+    $nice_lang = array();
++    /**
++     * instructions for using this page
++     *
++     * @return string localised instructions for using the page
++     */
++
++    function get_instructions()
++    {
++        return '';
++    }
 +
-+    $all_languages = common_config('site', 'languages');
++    /**
++     * do structured output for the "instructions" are of the page
++     *
++     * @return void
++     */
 +
-+    foreach ($all_languages as $lang) {
-+        $nice_lang = $nice_lang + array($lang['lang'] => $lang['name']);
++    function show_top()
++    {
++        $cur = common_current_user();
++
++        common_message_form(null, $cur, null);
++
++        $this->views_menu();
 +    }
-+    return $nice_lang;
-+}
 +
-+/**
-+ * Get a list of all languages that are enabled in the default config
-+ *
-+ * This should ONLY be called when setting up the default config in common.php.
-+ * Any other attempt to get a list of lanugages should instead call
-+ * common_config('site','languages')
-+ *
-+ * @return array mapping of language codes to language info
-+ */
++    /**
++     * show a full page of output
++     *
++     * @param User $user The current user
++     * @param int  $page The page the user is on
++     *
++     * @return void
++     */
 +
-+function get_all_languages()
-+{
-+    return
-+      array('en-us' => array('q' => 1, 'lang' => 'en_US',
-+                             'name' => 'English (US)', 'direction' => 'ltr'),
-+            'en-nz' => array('q' => 1, 'lang' => 'en_NZ',
-+                             'name' => 'English (NZ)', 'direction' => 'ltr'),
-+            'en-gb' => array('q' => 1, 'lang' => 'en_GB',
-+                             'name' => 'English (British)', 'direction' => 'ltr'),
-+            'en' => array('q' => 1, 'lang' => 'en',
-+                          'name' => 'English', 'direction' => 'ltr'),
-+            'da' => array('q' => 0.1, 'lang' => 'da_DK',
-+                          'name' => 'Danish', 'direction' => 'ltr'),
-+            'nl' => array('q' => 1, 'lang' => 'nl_NL',
-+                          'name' => 'Dutch', 'direction' => 'ltr'),
-+            'eo' => array('q' => 0.1, 'lang' => 'eo',
-+                          'name' => 'Esperanto', 'direction' => 'ltr'),
-+            'fr-fr' => array('q' => 0.9, 'lang' => 'fr_FR',
-+                             'name' => 'French', 'direction' => 'ltr'),
-+            'de' => array('q' => 1, 'lang' => 'de_DE',
-+                          'name' => 'German', 'direction' => 'ltr'),
-+            'it' => array('q' => 1, 'lang' => 'it_IT',
-+                          'name' => 'Italian', 'direction' => 'ltr'),
-+            'ko' => array('q' => 0.1, 'lang' => 'ko',
-+                          'name' => 'Korean', 'direction' => 'ltr'),
-+            'nb' => array('q' => 1, 'lang' => 'nb_NO',
-+                          'name' => 'Norwegian (bokmal)', 'direction' => 'ltr'),
-+            'pt' => array('q' => 0.2, 'lang' => 'pt',
-+                          'name' => 'Portuguese', 'direction' => 'ltr'),
-+            'pt-br' => array('q' => 1, 'lang' => 'pt_BR',
-+                             'name' => 'Portuguese Brazil', 'direction' => 'ltr'),
-+            'es' => array('q' => 1, 'lang' => 'es',
-+                          'name' => 'Spanish', 'direction' => 'ltr'),
-+            'tr' => array('q' => 1, 'lang' => 'tr_TR',
-+                          'name' => 'Turkish', 'direction' => 'ltr'),
-+            'uk' => array('q' => 1, 'lang' => 'uk_UA',
-+                          'name' => 'Ukrainian', 'direction' => 'ltr'),
-+            'pl' => array('q' => 1, 'lang' => 'pl_PL',
-+                          'name' => 'Polish', 'direction' => 'ltr'),
-+            'mk' => array('q' => 1, 'lang' => 'mk_MK',
-+                          'name' => 'Macedonian', 'direction' => 'ltr'),
-+            'jp' => array('q' => 0.1, 'lang' => 'ja_JP',
-+                          'name' => 'Japanese', 'direction' => 'ltr'),
-+            'cs' => array('q' => 1, 'lang' => 'cs_CZ',
-+                          'name' => 'Czech', 'direction' => 'ltr'),
-+            'ca' => array('q' => 1, 'lang' => 'ca_ES',
-+                          'name' => 'Catalan', 'direction' => 'ltr'),
-+            );
++    function show_page($user, $page)
++    {
++        common_show_header($this->get_title($user, $page),
++                           null, null,
++                           array($this, 'show_top'));
++
++        $this->show_box($user, $page);
++
++        common_show_footer();
++    }
++
++    /**
++     * show the messages for a mailbox in list format
++     *
++     * Includes the pagination links (before, after).
++     *
++     * @param User $user The current user
++     * @param int  $page The page the user is on
++     *
++     * @return void
++     */
++
++    function show_box($user, $page)
++    {
++        $message = $this->get_messages($user, $page);
++
++        if ($message) {
++
++            $cnt = 0;
++            common_element_start('ul', array('id' => 'messages'));
++
++            while ($message->fetch() && $cnt <= MESSAGES_PER_PAGE) {
++                $cnt++;
+hunk ./lib/mailbox.php 180
+-		parent::handle($args);
++                if ($cnt > MESSAGES_PER_PAGE) {
++                    break;
++                }
+hunk ./lib/mailbox.php 184
+-		$nickname = common_canonical_nickname($this->arg('nickname'));
+-		$user = User::staticGet('nickname', $nickname);
++                $this->show_message($message);
++            }
+hunk ./lib/mailbox.php 187
+-		if (!$user) {
+-			$this->client_error(_('No such user.'), 404);
+-			return;
+-		}
++            common_element_end('ul');
+hunk ./lib/mailbox.php 189
+-		$cur = common_current_user();
+-		
+-		if (!$cur || $cur->id != $user->id) {
+-			$this->client_error(_('Only the user can read their own mailboxes.'), 403);
+-			return;
+-		}
+-		
+-		$profile = $user->getProfile();
++            common_pagination($page > 1, $cnt > MESSAGES_PER_PAGE,
++                              $page, $this->trimmed('action'),
++                              array('nickname' => $user->nickname));
+hunk ./lib/mailbox.php 193
+-		if (!$profile) {
+-			$this->server_error(_('User has no profile.'));
+-			return;
+-		}
++            $message->free();
++            unset($message);
++        }
++    }
+hunk ./lib/mailbox.php 198
+-		$page = $this->trimmed('page');
+-		
+-		if (!$page) {
+-			$page = 1;
+-		}
+-		
+-		$this->show_page($user, $page);
+-	}
++    /**
++     * returns the profile we want to show with the message
++     *
++     * For inboxes, we show the sender; for outboxes, the recipient.
++     *
++     * @param Message $message The message to get the profile for
++     *
++     * @return Profile The profile that matches the message
++     */
+hunk ./lib/mailbox.php 208
+-	function get_title($user, $page) {
+-		return '';
+-	}
++    function get_message_profile($message)
++    {
++        return null;
++    }
+hunk ./lib/mailbox.php 213
+-	function get_instructions() {
+-		return '';
+-	}
++    /**
++     * show a single message in the list format
++     *
++     * @param Message $message the message to show
++     *
++     * @return void
++     */
+hunk ./lib/mailbox.php 221
+-	function show_top() {
++    function show_message($message)
++    {
++        common_element_start('li', array('class' => 'message_single',
++                                         'id' => 'message-' . $message->id));
+hunk ./lib/mailbox.php 226
+-		$cur = common_current_user();
+-		
+-		common_message_form(NULL, $cur, NULL);
+-		
+-		$this->views_menu();
+-	}
+-	
+-	function show_page($user, $page) {
++        $profile = $this->get_message_profile($message);
+hunk ./lib/mailbox.php 228
+-		common_show_header($this->get_title($user, $page),
+-						   NULL, NULL,
+-						   array($this, 'show_top'));
+-		
+-		$this->show_box($user, $page);
+-		
+-		common_show_footer();
+-	}
+-	
+-	function show_box($user, $page) {
+-		
+-		$message = $this->get_messages($user, $page);
+-		
+-		if ($message) {
+-			
+-			$cnt = 0;
+-			common_element_start('ul', array('id' => 'messages'));
+-		
+-			while ($message->fetch() && $cnt <= MESSAGES_PER_PAGE) {
+-				$cnt++;
+-				
+-				if ($cnt > MESSAGES_PER_PAGE) {
+-					break;
+-				}
+-				
+-				$this->show_message($message);
+-			}
++        $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
++        common_element_start('a', array('href' => $profile->profileurl));
++        common_element('img', array('src' => ($avatar) ?
++                                    common_avatar_display_url($avatar) :
++                                    common_default_avatar(AVATAR_STREAM_SIZE),
++                                    'class' => 'avatar stream',
++                                    'width' => AVATAR_STREAM_SIZE,
++                                    'height' => AVATAR_STREAM_SIZE,
++                                    'alt' =>
++                                    ($profile->fullname) ? $profile->fullname :
++                                    $profile->nickname));
++        common_element_end('a');
++        common_element('a', array('href' => $profile->profileurl,
++                                  'class' => 'nickname'),
++                       $profile->nickname);
++        // FIXME: URL, image, video, audio
++        common_element_start('p', array('class' => 'content'));
++        common_raw($message->rendered);
++        common_element_end('p');
+hunk ./lib/mailbox.php 248
+-			common_element_end('ul');
+-			
+-			common_pagination($page > 1, $cnt > MESSAGES_PER_PAGE,
+-							  $page, $this->trimmed('action'),
+-							  array('nickname' => $user->nickname));
+-			
+-			$message->free();
+-			unset($message);
+-		}
+-	}
++        $messageurl = common_local_url('showmessage',
++                                       array('message' => $message->id));
+hunk ./lib/mailbox.php 251
+-	# returns the profile we want to show with the message
+-	
+-	function get_message_profile($message) {
+-		return NULL;
+-	}
+-	
+-	function show_message($message) {
++        // XXX: we need to figure this out better. Is this right?
++        if (strcmp($message->uri, $messageurl) != 0 &&
++            preg_match('/^http/', $message->uri)) {
++            $messageurl = $message->uri;
++        }
++        common_element_start('p', 'time');
++        common_element('a', array('class' => 'permalink',
++                                  'href' => $messageurl,
++                                  'title' => common_exact_date($message->created)),
++                       common_date_string($message->created));
++        if ($message->source) {
++            common_text(_(' from '));
++            $this->source_link($message->source);
++        }
+hunk ./lib/mailbox.php 266
+-		common_element_start('li', array('class' => 'message_single',
+-										  'id' => 'message-' . $message->id));
++        common_element_end('p');
+hunk ./lib/mailbox.php 268
+-		$profile = $this->get_message_profile($message);
+-		
+-		$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
+-		common_element_start('a', array('href' => $profile->profileurl));
+-		common_element('img', array('src' => ($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_STREAM_SIZE),
+-									'class' => 'avatar stream',
+-									'width' => AVATAR_STREAM_SIZE,
+-									'height' => AVATAR_STREAM_SIZE,
+-									'alt' =>
+-									($profile->fullname) ? $profile->fullname :
+-									$profile->nickname));
+-		common_element_end('a');
+-		common_element('a', array('href' => $profile->profileurl,
+-								  'class' => 'nickname'),
+-					   $profile->nickname);
+-		# FIXME: URL, image, video, audio
+-		common_element_start('p', array('class' => 'content'));
+-		common_raw($message->rendered);
+-		common_element_end('p');
+-		
+-		$messageurl = common_local_url('showmessage', array('message' => $message->id));
+-		
+-		# XXX: we need to figure this out better. Is this right?
+-		if (strcmp($message->uri, $messageurl) != 0 && preg_match('/^http/', $message->uri)) {
+-			$messageurl = $message->uri;
+-		}
+-		common_element_start('p', 'time');
+-		common_element('a', array('class' => 'permalink',
+-								  'href' => $messageurl,
+-								  'title' => common_exact_date($message->created)),
+-					   common_date_string($message->created));
+-		if ($message->source) {
+-			common_text(_(' from '));
+-			$this->source_link($message->source);
+-		}
+-		
+-		common_element_end('p');
+-		
+-		common_element_end('li');
+-	}
++        common_element_end('li');
++    }
diff --git a/lib/mailbox.php b/lib/mailbox.php
index 4ed8d17582..9039c5fdaa 100644
--- a/lib/mailbox.php
+++ b/lib/mailbox.php
@@ -1,9 +1,12 @@
 <?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
+/**
+ * Laconica, the distributed open-source microblogging tool
  *
- * This program is free software: you can redistribute it and/or modify
+ * 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.
@@ -15,158 +18,253 @@
  *
  * 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  Action
+ * @package   Laconica
+ * @author    Evan Prodromou <evan@controlyourself.ca>
+ * @copyright 2008 Control Yourself, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://laconi.ca/
  */
 
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('LACONICA')) {
+    exit(1);
+}
 
-require_once(INSTALLDIR.'/lib/personal.php');
+require_once INSTALLDIR.'/lib/personal.php';
 
 define('MESSAGES_PER_PAGE', 20);
 
-class MailboxAction extends PersonalAction {
-	
-	function handle($args) {
-
-		parent::handle($args);
-
-		$nickname = common_canonical_nickname($this->arg('nickname'));
-		$user = User::staticGet('nickname', $nickname);
-
-		if (!$user) {
-			$this->client_error(_('No such user.'), 404);
-			return;
-		}
-
-		$cur = common_current_user();
-		
-		if (!$cur || $cur->id != $user->id) {
-			$this->client_error(_('Only the user can read their own mailboxes.'), 403);
-			return;
-		}
-		
-		$profile = $user->getProfile();
-
-		if (!$profile) {
-			$this->server_error(_('User has no profile.'));
-			return;
-		}
-
-		$page = $this->trimmed('page');
-		
-		if (!$page) {
-			$page = 1;
-		}
-		
-		$this->show_page($user, $page);
-	}
-
-	function get_title($user, $page) {
-		return '';
-	}
-
-	function get_instructions() {
-		return '';
-	}
-
-	function show_top() {
-
-		$cur = common_current_user();
-		
-		common_message_form(NULL, $cur, NULL);
-		
-		$this->views_menu();
-	}
-	
-	function show_page($user, $page) {
-
-		common_show_header($this->get_title($user, $page),
-						   NULL, NULL,
-						   array($this, 'show_top'));
-		
-		$this->show_box($user, $page);
-		
-		common_show_footer();
-	}
-	
-	function show_box($user, $page) {
-		
-		$message = $this->get_messages($user, $page);
-		
-		if ($message) {
-			
-			$cnt = 0;
-			common_element_start('ul', array('id' => 'messages'));
-		
-			while ($message->fetch() && $cnt <= MESSAGES_PER_PAGE) {
-				$cnt++;
-				
-				if ($cnt > MESSAGES_PER_PAGE) {
-					break;
-				}
-				
-				$this->show_message($message);
-			}
-
-			common_element_end('ul');
-			
-			common_pagination($page > 1, $cnt > MESSAGES_PER_PAGE,
-							  $page, $this->trimmed('action'),
-							  array('nickname' => $user->nickname));
-			
-			$message->free();
-			unset($message);
-		}
-	}
-
-	# returns the profile we want to show with the message
-	
-	function get_message_profile($message) {
-		return NULL;
-	}
-	
-	function show_message($message) {
-
-		common_element_start('li', array('class' => 'message_single',
-										  'id' => 'message-' . $message->id));
-
-		$profile = $this->get_message_profile($message);
-		
-		$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
-		common_element_start('a', array('href' => $profile->profileurl));
-		common_element('img', array('src' => ($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_STREAM_SIZE),
-									'class' => 'avatar stream',
-									'width' => AVATAR_STREAM_SIZE,
-									'height' => AVATAR_STREAM_SIZE,
-									'alt' =>
-									($profile->fullname) ? $profile->fullname :
-									$profile->nickname));
-		common_element_end('a');
-		common_element('a', array('href' => $profile->profileurl,
-								  'class' => 'nickname'),
-					   $profile->nickname);
-		# FIXME: URL, image, video, audio
-		common_element_start('p', array('class' => 'content'));
-		common_raw($message->rendered);
-		common_element_end('p');
-		
-		$messageurl = common_local_url('showmessage', array('message' => $message->id));
-		
-		# XXX: we need to figure this out better. Is this right?
-		if (strcmp($message->uri, $messageurl) != 0 && preg_match('/^http/', $message->uri)) {
-			$messageurl = $message->uri;
-		}
-		common_element_start('p', 'time');
-		common_element('a', array('class' => 'permalink',
-								  'href' => $messageurl,
-								  'title' => common_exact_date($message->created)),
-					   common_date_string($message->created));
-		if ($message->source) {
-			common_text(_(' from '));
-			$this->source_link($message->source);
-		}
-		
-		common_element_end('p');
-		
-		common_element_end('li');
-	}
+/**
+ * common superclass for direct messages inbox and outbox
+ *
+ * @category Action
+ * @package  Laconica
+ * @author   Evan Prodromou <evan@controlyourself.ca>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://laconi.ca/
+ * @see      InboxAction
+ * @see      OutboxAction
+ */
+
+class MailboxAction extends PersonalAction
+{
+    /**
+     * output page based on arguments
+     *
+     * @param array $args HTTP arguments (from $_REQUEST)
+     *
+     * @return void
+     */
+
+    function handle($args)
+    {
+        parent::handle($args);
+
+        $nickname = common_canonical_nickname($this->arg('nickname'));
+
+        $user = User::staticGet('nickname', $nickname);
+
+        if (!$user) {
+            $this->client_error(_('No such user.'), 404);
+            return;
+        }
+
+        $cur = common_current_user();
+
+        if (!$cur || $cur->id != $user->id) {
+            $this->client_error(_('Only the user can read their own mailboxes.'),
+                                403);
+            return;
+        }
+
+        $profile = $user->getProfile();
+
+        if (!$profile) {
+            $this->server_error(_('User has no profile.'));
+            return;
+        }
+
+        $page = $this->trimmed('page');
+
+        if (!$page) {
+            $page = 1;
+        }
+
+        $this->show_page($user, $page);
+    }
+
+    /**
+     * returns the title of the page
+     *
+     * @param User $user current user
+     * @param int  $page current page
+     *
+     * @return string localised title of the page
+     */
+
+    function get_title($user, $page)
+    {
+        return '';
+    }
+
+    /**
+     * instructions for using this page
+     *
+     * @return string localised instructions for using the page
+     */
+
+    function get_instructions()
+    {
+        return '';
+    }
+
+    /**
+     * do structured output for the "instructions" are of the page
+     *
+     * @return void
+     */
+
+    function show_top()
+    {
+        $cur = common_current_user();
+
+        common_message_form(null, $cur, null);
+
+        $this->views_menu();
+    }
+
+    /**
+     * show a full page of output
+     *
+     * @param User $user The current user
+     * @param int  $page The page the user is on
+     *
+     * @return void
+     */
+
+    function show_page($user, $page)
+    {
+        common_show_header($this->get_title($user, $page),
+                           null, null,
+                           array($this, 'show_top'));
+
+        $this->show_box($user, $page);
+
+        common_show_footer();
+    }
+
+    /**
+     * show the messages for a mailbox in list format
+     *
+     * Includes the pagination links (before, after).
+     *
+     * @param User $user The current user
+     * @param int  $page The page the user is on
+     *
+     * @return void
+     */
+
+    function show_box($user, $page)
+    {
+        $message = $this->get_messages($user, $page);
+
+        if ($message) {
+
+            $cnt = 0;
+            common_element_start('ul', array('id' => 'messages'));
+
+            while ($message->fetch() && $cnt <= MESSAGES_PER_PAGE) {
+                $cnt++;
+
+                if ($cnt > MESSAGES_PER_PAGE) {
+                    break;
+                }
+
+                $this->show_message($message);
+            }
+
+            common_element_end('ul');
+
+            common_pagination($page > 1, $cnt > MESSAGES_PER_PAGE,
+                              $page, $this->trimmed('action'),
+                              array('nickname' => $user->nickname));
+
+            $message->free();
+            unset($message);
+        }
+    }
+
+    /**
+     * returns the profile we want to show with the message
+     *
+     * For inboxes, we show the sender; for outboxes, the recipient.
+     *
+     * @param Message $message The message to get the profile for
+     *
+     * @return Profile The profile that matches the message
+     */
+
+    function get_message_profile($message)
+    {
+        return null;
+    }
+
+    /**
+     * show a single message in the list format
+     *
+     * @param Message $message the message to show
+     *
+     * @return void
+     */
+
+    function show_message($message)
+    {
+        common_element_start('li', array('class' => 'message_single',
+                                         'id' => 'message-' . $message->id));
+
+        $profile = $this->get_message_profile($message);
+
+        $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
+        common_element_start('a', array('href' => $profile->profileurl));
+        common_element('img', array('src' => ($avatar) ?
+                                    common_avatar_display_url($avatar) :
+                                    common_default_avatar(AVATAR_STREAM_SIZE),
+                                    'class' => 'avatar stream',
+                                    'width' => AVATAR_STREAM_SIZE,
+                                    'height' => AVATAR_STREAM_SIZE,
+                                    'alt' =>
+                                    ($profile->fullname) ? $profile->fullname :
+                                    $profile->nickname));
+        common_element_end('a');
+        common_element('a', array('href' => $profile->profileurl,
+                                  'class' => 'nickname'),
+                       $profile->nickname);
+        // FIXME: URL, image, video, audio
+        common_element_start('p', array('class' => 'content'));
+        common_raw($message->rendered);
+        common_element_end('p');
+
+        $messageurl = common_local_url('showmessage',
+                                       array('message' => $message->id));
+
+        // XXX: we need to figure this out better. Is this right?
+        if (strcmp($message->uri, $messageurl) != 0 &&
+            preg_match('/^http/', $message->uri)) {
+            $messageurl = $message->uri;
+        }
+        common_element_start('p', 'time');
+        common_element('a', array('class' => 'permalink',
+                                  'href' => $messageurl,
+                                  'title' => common_exact_date($message->created)),
+                       common_date_string($message->created));
+        if ($message->source) {
+            common_text(_(' from '));
+            $this->source_link($message->source);
+        }
+
+        common_element_end('p');
+
+        common_element_end('li');
+    }
 }
-- 
2.39.5