Index: branches/comu/data/module/Mail/mimeDecode.php
===================================================================
--- branches/comu/data/module/Mail/mimeDecode.php	(revision 11984)
+++ branches/comu/data/module/Mail/mimeDecode.php	(revision 11984)
@@ -0,0 +1,837 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003  Richard Heyes                                |
+// | Copyright (c) 2003-2005  The PHP Group                                |
+// | All rights reserved.                                                  |
+// |                                                                       |
+// | Redistribution and use in source and binary forms, with or without    |
+// | modification, are permitted provided that the following conditions    |
+// | are met:                                                              |
+// |                                                                       |
+// | o Redistributions of source code must retain the above copyright      |
+// |   notice, this list of conditions and the following disclaimer.       |
+// | o Redistributions in binary form must reproduce the above copyright   |
+// |   notice, this list of conditions and the following disclaimer in the |
+// |   documentation and/or other materials provided with the distribution.|
+// | o The names of the authors may not be used to endorse or promote      |
+// |   products derived from this software without specific prior written  |
+// |   permission.                                                         |
+// |                                                                       |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
+// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
+// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
+// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
+// |                                                                       |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard@phpguru.org>                           |
+// +-----------------------------------------------------------------------+
+
+require_once dirname(__FILE__) . '/../PEAR.php';
+
+/**
+*  +----------------------------- IMPORTANT ------------------------------+
+*  | Usage of this class compared to native php extensions such as        |
+*  | mailparse or imap, is slow and may be feature deficient. If available|
+*  | you are STRONGLY recommended to use the php extensions.              |
+*  +----------------------------------------------------------------------+
+*
+* Mime Decoding class
+*
+* This class will parse a raw mime email and return
+* the structure. Returned structure is similar to
+* that returned by imap_fetchstructure().
+*
+* USAGE: (assume $input is your raw email)
+*
+* $decode = new Mail_mimeDecode($input, "\r\n");
+* $structure = $decode->decode();
+* print_r($structure);
+*
+* Or statically:
+*
+* $params['input'] = $input;
+* $structure = Mail_mimeDecode::decode($params);
+* print_r($structure);
+*
+* TODO:
+*  o Implement multipart/appledouble
+*  o UTF8: ???
+
+		> 4. We have also found a solution for decoding the UTF-8 
+		> headers. Therefore I made the following function:
+		> 
+		> function decode_utf8($txt) {
+		> $trans=array("Å&#8216;"=>"Ãµ","Å±"=>"Ã»","Å"=>"Ã&#8226;","Å°"
+		=>"Ã&#8250;");
+		> $txt=strtr($txt,$trans);
+		> return(utf8_decode($txt));
+		> }
+		> 
+		> And I have inserted the following line to the class:
+		> 
+		> if (strtolower($charset)=="utf-8") $text=decode_utf8($text);
+		> 
+		> ... before the following one in the "_decodeHeader" function:
+		> 
+		> $input = str_replace($encoded, $text, $input);
+		> 
+		> This way from now on it can easily decode the UTF-8 headers too.
+
+*
+* @author  Richard Heyes <richard@phpguru.org>
+* @version $Revision: 1.46 $
+* @package Mail
+*/
+class Mail_mimeDecode extends PEAR
+{
+    /**
+     * The raw email to decode
+     * @var    string
+     */
+    var $_input;
+
+    /**
+     * The header part of the input
+     * @var    string
+     */
+    var $_header;
+
+    /**
+     * The body part of the input
+     * @var    string
+     */
+    var $_body;
+
+    /**
+     * If an error occurs, this is used to store the message
+     * @var    string
+     */
+    var $_error;
+
+    /**
+     * Flag to determine whether to include bodies in the
+     * returned object.
+     * @var    boolean
+     */
+    var $_include_bodies;
+
+    /**
+     * Flag to determine whether to decode bodies
+     * @var    boolean
+     */
+    var $_decode_bodies;
+
+    /**
+     * Flag to determine whether to decode headers
+     * @var    boolean
+     */
+    var $_decode_headers;
+
+    /**
+     * Constructor.
+     *
+     * Sets up the object, initialise the variables, and splits and
+     * stores the header and body of the input.
+     *
+     * @param string The input to decode
+     * @access public
+     */
+    function Mail_mimeDecode($input)
+    {
+        list($header, $body)   = $this->_splitBodyHeader($input);
+
+        $this->_input          = $input;
+        $this->_header         = $header;
+        $this->_body           = $body;
+        $this->_decode_bodies  = false;
+        $this->_include_bodies = true;
+    }
+
+    /**
+     * Begins the decoding process. If called statically
+     * it will create an object and call the decode() method
+     * of it.
+     *
+     * @param array An array of various parameters that determine
+     *              various things:
+     *              include_bodies - Whether to include the body in the returned
+     *                               object.
+     *              decode_bodies  - Whether to decode the bodies
+     *                               of the parts. (Transfer encoding)
+     *              decode_headers - Whether to decode headers
+     *              input          - If called statically, this will be treated
+     *                               as the input
+     * @return object Decoded results
+     * @access public
+     */
+    function decode($params = null)
+    {
+        // determine if this method has been called statically
+        $isStatic = !(isset($this) && get_class($this) == __CLASS__);
+
+        // Have we been called statically?
+	// If so, create an object and pass details to that.
+        if ($isStatic AND isset($params['input'])) {
+
+            $obj = new Mail_mimeDecode($params['input']);
+            $structure = $obj->decode($params);
+
+        // Called statically but no input
+        } elseif ($isStatic) {
+            return PEAR::raiseError('Called statically and no input given');
+
+        // Called via an object
+        } else {
+            $this->_include_bodies = isset($params['include_bodies']) ?
+	                             $params['include_bodies'] : false;
+            $this->_decode_bodies  = isset($params['decode_bodies']) ?
+	                             $params['decode_bodies']  : false;
+            $this->_decode_headers = isset($params['decode_headers']) ?
+	                             $params['decode_headers'] : false;
+
+            $structure = $this->_decode($this->_header, $this->_body);
+            if ($structure === false) {
+                $structure = $this->raiseError($this->_error);
+            }
+        }
+
+        return $structure;
+    }
+
+    /**
+     * Performs the decoding. Decodes the body string passed to it
+     * If it finds certain content-types it will call itself in a
+     * recursive fashion
+     *
+     * @param string Header section
+     * @param string Body section
+     * @return object Results of decoding process
+     * @access private
+     */
+    function _decode($headers, $body, $default_ctype = 'text/plain')
+    {
+        $return = new stdClass;
+        $return->headers = array();
+        $headers = $this->_parseHeaders($headers);
+
+        foreach ($headers as $value) {
+            if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) {
+                $return->headers[strtolower($value['name'])]   = array($return->headers[strtolower($value['name'])]);
+                $return->headers[strtolower($value['name'])][] = $value['value'];
+
+            } elseif (isset($return->headers[strtolower($value['name'])])) {
+                $return->headers[strtolower($value['name'])][] = $value['value'];
+
+            } else {
+                $return->headers[strtolower($value['name'])] = $value['value'];
+            }
+        }
+
+        reset($headers);
+        while (list($key, $value) = each($headers)) {
+            $headers[$key]['name'] = strtolower($headers[$key]['name']);
+            switch ($headers[$key]['name']) {
+
+                case 'content-type':
+                    $content_type = $this->_parseHeaderValue($headers[$key]['value']);
+
+                    if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) {
+                        $return->ctype_primary   = $regs[1];
+                        $return->ctype_secondary = $regs[2];
+                    }
+
+                    if (isset($content_type['other'])) {
+                        while (list($p_name, $p_value) = each($content_type['other'])) {
+                            $return->ctype_parameters[$p_name] = $p_value;
+                        }
+                    }
+                    break;
+
+                case 'content-disposition':
+                    $content_disposition = $this->_parseHeaderValue($headers[$key]['value']);
+                    $return->disposition   = $content_disposition['value'];
+                    if (isset($content_disposition['other'])) {
+                        while (list($p_name, $p_value) = each($content_disposition['other'])) {
+                            $return->d_parameters[$p_name] = $p_value;
+                        }
+                    }
+                    break;
+
+                case 'content-transfer-encoding':
+                    $content_transfer_encoding = $this->_parseHeaderValue($headers[$key]['value']);
+                    break;
+            }
+        }
+
+        if (isset($content_type)) {
+            switch (strtolower($content_type['value'])) {
+                case 'text/plain':
+                    $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
+                    $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null;
+                    break;
+
+                case 'text/html':
+                    $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
+                    $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null;
+                    break;
+
+                case 'multipart/parallel':
+                case 'multipart/report': // RFC1892
+                case 'multipart/signed': // PGP
+                case 'multipart/digest':
+                case 'multipart/alternative':
+                case 'multipart/related':
+                case 'multipart/mixed':
+                    if(!isset($content_type['other']['boundary'])){
+                        $this->_error = 'No boundary found for ' . $content_type['value'] . ' part';
+                        return false;
+                    }
+
+                    $default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain';
+
+                    $parts = $this->_boundarySplit($body, $content_type['other']['boundary']);
+                    for ($i = 0; $i < count($parts); $i++) {
+                        list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]);
+                        $part = $this->_decode($part_header, $part_body, $default_ctype);
+                        if($part === false)
+                            $part = $this->raiseError($this->_error);
+                        $return->parts[] = $part;
+                    }
+                    break;
+
+                case 'message/rfc822':
+                    $obj = &new Mail_mimeDecode($body);
+                    $return->parts[] = $obj->decode(array('include_bodies' => $this->_include_bodies,
+					                                      'decode_bodies'  => $this->_decode_bodies,
+														  'decode_headers' => $this->_decode_headers));
+                    unset($obj);
+                    break;
+
+                default:
+                    if(!isset($content_transfer_encoding['value']))
+                        $content_transfer_encoding['value'] = '7bit';
+                    $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $content_transfer_encoding['value']) : $body) : null;
+                    break;
+            }
+
+        } else {
+            $ctype = explode('/', $default_ctype);
+            $return->ctype_primary   = $ctype[0];
+            $return->ctype_secondary = $ctype[1];
+            $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body) : $body) : null;
+        }
+
+        return $return;
+    }
+
+    /**
+     * Given the output of the above function, this will return an
+     * array of references to the parts, indexed by mime number.
+     *
+     * @param  object $structure   The structure to go through
+     * @param  string $mime_number Internal use only.
+     * @return array               Mime numbers
+     */
+    function &getMimeNumbers(&$structure, $no_refs = false, $mime_number = '', $prepend = '')
+    {
+        $return = array();
+        if (!empty($structure->parts)) {
+            if ($mime_number != '') {
+                $structure->mime_id = $prepend . $mime_number;
+                $return[$prepend . $mime_number] = &$structure;
+            }
+            for ($i = 0; $i < count($structure->parts); $i++) {
+
+            
+                if (!empty($structure->headers['content-type']) AND substr(strtolower($structure->headers['content-type']), 0, 8) == 'message/') {
+                    $prepend      = $prepend . $mime_number . '.';
+                    $_mime_number = '';
+                } else {
+                    $_mime_number = ($mime_number == '' ? $i + 1 : sprintf('%s.%s', $mime_number, $i + 1));
+                }
+
+                $arr = &Mail_mimeDecode::getMimeNumbers($structure->parts[$i], $no_refs, $_mime_number, $prepend);
+                foreach ($arr as $key => $val) {
+                    $no_refs ? $return[$key] = '' : $return[$key] = &$arr[$key];
+                }
+            }
+        } else {
+            if ($mime_number == '') {
+                $mime_number = '1';
+            }
+            $structure->mime_id = $prepend . $mime_number;
+            $no_refs ? $return[$prepend . $mime_number] = '' : $return[$prepend . $mime_number] = &$structure;
+        }
+        
+        return $return;
+    }
+
+    /**
+     * Given a string containing a header and body
+     * section, this function will split them (at the first
+     * blank line) and return them.
+     *
+     * @param string Input to split apart
+     * @return array Contains header and body section
+     * @access private
+     */
+    function _splitBodyHeader($input)
+    {
+        if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) {
+            return array($match[1], $match[2]);
+        }
+        $this->_error = 'Could not split header and body';
+        return false;
+    }
+
+    /**
+     * Parse headers given in $input and return
+     * as assoc array.
+     *
+     * @param string Headers to parse
+     * @return array Contains parsed headers
+     * @access private
+     */
+    function _parseHeaders($input)
+    {
+
+        if ($input !== '') {
+            // Unfold the input
+            $input   = preg_replace("/\r?\n/", "\r\n", $input);
+            $input   = preg_replace("/\r\n(\t| )+/", ' ', $input);
+            $headers = explode("\r\n", trim($input));
+
+            foreach ($headers as $value) {
+                $hdr_name = substr($value, 0, $pos = strpos($value, ':'));
+                $hdr_value = substr($value, $pos+1);
+                if($hdr_value[0] == ' ')
+                    $hdr_value = substr($hdr_value, 1);
+
+                $return[] = array(
+                                  'name'  => $hdr_name,
+                                  'value' => $this->_decode_headers ? $this->_decodeHeader($hdr_value) : $hdr_value
+                                 );
+            }
+        } else {
+            $return = array();
+        }
+
+        return $return;
+    }
+
+    /**
+     * Function to parse a header value,
+     * extract first part, and any secondary
+     * parts (after ;) This function is not as
+     * robust as it could be. Eg. header comments
+     * in the wrong place will probably break it.
+     *
+     * @param string Header value to parse
+     * @return array Contains parsed result
+     * @access private
+     */
+    function _parseHeaderValue($input)
+    {
+
+        if (($pos = strpos($input, ';')) !== false) {
+
+            $return['value'] = trim(substr($input, 0, $pos));
+            $input = trim(substr($input, $pos+1));
+
+            if (strlen($input) > 0) {
+
+                // This splits on a semi-colon, if there's no preceeding backslash
+                // Now works with quoted values; had to glue the \; breaks in PHP
+                // the regex is already bordering on incomprehensible
+                $splitRegex = '/([^;\'"]*[\'"]([^\'"]*([^\'"]*)*)[\'"][^;\'"]*|([^;]+))(;|$)/';
+                preg_match_all($splitRegex, $input, $matches);
+                $parameters = array();
+                for ($i=0; $i<count($matches[0]); $i++) {
+                    $param = $matches[0][$i];
+                    while (substr($param, -2) == '\;') {
+                        $param .= $matches[0][++$i];
+                    }
+                    $parameters[] = $param;
+                }
+
+                for ($i = 0; $i < count($parameters); $i++) {
+                    $param_name  = trim(substr($parameters[$i], 0, $pos = strpos($parameters[$i], '=')), "'\";\t\\ ");
+                    $param_value = trim(str_replace('\;', ';', substr($parameters[$i], $pos + 1)), "'\";\t\\ ");
+                    if ($param_value[0] == '"') {
+                        $param_value = substr($param_value, 1, -1);
+                    }
+                    $return['other'][$param_name] = $param_value;
+                    $return['other'][strtolower($param_name)] = $param_value;
+                }
+            }
+        } else {
+            $return['value'] = trim($input);
+        }
+
+        return $return;
+    }
+
+    /**
+     * This function splits the input based
+     * on the given boundary
+     *
+     * @param string Input to parse
+     * @return array Contains array of resulting mime parts
+     * @access private
+     */
+    function _boundarySplit($input, $boundary)
+    {
+        $parts = array();
+
+        $bs_possible = substr($boundary, 2, -2);
+        $bs_check = '\"' . $bs_possible . '\"';
+
+        if ($boundary == $bs_check) {
+            $boundary = $bs_possible;
+        }
+
+        $tmp = explode('--' . $boundary, $input);
+
+        for ($i = 1; $i < count($tmp) - 1; $i++) {
+            $parts[] = $tmp[$i];
+        }
+
+        return $parts;
+    }
+
+    /**
+     * Given a header, this function will decode it
+     * according to RFC2047. Probably not *exactly*
+     * conformant, but it does pass all the given
+     * examples (in RFC2047).
+     *
+     * @param string Input header value to decode
+     * @return string Decoded header value
+     * @access private
+     */
+    function _decodeHeader($input)
+    {
+        // Remove white space between encoded-words
+        $input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input);
+
+        // For each encoded-word...
+        while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) {
+
+            $encoded  = $matches[1];
+            $charset  = $matches[2];
+            $encoding = $matches[3];
+            $text     = $matches[4];
+
+            switch (strtolower($encoding)) {
+                case 'b':
+                    $text = base64_decode($text);
+                    break;
+
+                case 'q':
+                    $text = str_replace('_', ' ', $text);
+                    preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
+                    foreach($matches[1] as $value)
+                        $text = str_replace('='.$value, chr(hexdec($value)), $text);
+                    break;
+            }
+
+            $input = str_replace($encoded, $text, $input);
+        }
+
+        return $input;
+    }
+
+    /**
+     * Given a body string and an encoding type,
+     * this function will decode and return it.
+     *
+     * @param  string Input body to decode
+     * @param  string Encoding type to use.
+     * @return string Decoded body
+     * @access private
+     */
+    function _decodeBody($input, $encoding = '7bit')
+    {
+        switch (strtolower($encoding)) {
+            case '7bit':
+                return $input;
+                break;
+
+            case 'quoted-printable':
+                return $this->_quotedPrintableDecode($input);
+                break;
+
+            case 'base64':
+                return base64_decode($input);
+                break;
+
+            default:
+                return $input;
+        }
+    }
+
+    /**
+     * Given a quoted-printable string, this
+     * function will decode and return it.
+     *
+     * @param  string Input body to decode
+     * @return string Decoded body
+     * @access private
+     */
+    function _quotedPrintableDecode($input)
+    {
+        // Remove soft line breaks
+        $input = preg_replace("/=\r?\n/", '', $input);
+
+        // Replace encoded characters
+		$input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input);
+
+        return $input;
+    }
+
+    /**
+     * Checks the input for uuencoded files and returns
+     * an array of them. Can be called statically, eg:
+     *
+     * $files =& Mail_mimeDecode::uudecode($some_text);
+     *
+     * It will check for the begin 666 ... end syntax
+     * however and won't just blindly decode whatever you
+     * pass it.
+     *
+     * @param  string Input body to look for attahcments in
+     * @return array  Decoded bodies, filenames and permissions
+     * @access public
+     * @author Unknown
+     */
+    function &uudecode($input)
+    {
+        // Find all uuencoded sections
+        preg_match_all("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", $input, $matches);
+
+        for ($j = 0; $j < count($matches[3]); $j++) {
+
+            $str      = $matches[3][$j];
+            $filename = $matches[2][$j];
+            $fileperm = $matches[1][$j];
+
+            $file = '';
+            $str = preg_split("/\r?\n/", trim($str));
+            $strlen = count($str);
+
+            for ($i = 0; $i < $strlen; $i++) {
+                $pos = 1;
+                $d = 0;
+                $len=(int)(((ord(substr($str[$i],0,1)) -32) - ' ') & 077);
+
+                while (($d + 3 <= $len) AND ($pos + 4 <= strlen($str[$i]))) {
+                    $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
+                    $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
+                    $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
+                    $c3 = (ord(substr($str[$i],$pos+3,1)) ^ 0x20);
+                    $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
+
+                    $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));
+
+                    $file .= chr(((($c2 - ' ') & 077) << 6) |  (($c3 - ' ') & 077));
+
+                    $pos += 4;
+                    $d += 3;
+                }
+
+                if (($d + 2 <= $len) && ($pos + 3 <= strlen($str[$i]))) {
+                    $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
+                    $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
+                    $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
+                    $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
+
+                    $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));
+
+                    $pos += 3;
+                    $d += 2;
+                }
+
+                if (($d + 1 <= $len) && ($pos + 2 <= strlen($str[$i]))) {
+                    $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
+                    $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
+                    $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
+
+                }
+            }
+            $files[] = array('filename' => $filename, 'fileperm' => $fileperm, 'filedata' => $file);
+        }
+
+        return $files;
+    }
+
+    /**
+     * getSendArray() returns the arguments required for Mail::send()
+     * used to build the arguments for a mail::send() call 
+     *
+     * Usage:
+     * $mailtext = Full email (for example generated by a template)
+     * $decoder = new Mail_mimeDecode($mailtext);
+     * $parts =  $decoder->getSendArray();
+     * if (!PEAR::isError($parts) {
+     *     list($recipents,$headers,$body) = $parts;
+     *     $mail = Mail::factory('smtp');
+     *     $mail->send($recipents,$headers,$body);
+     * } else {
+     *     echo $parts->message;
+     * }
+     * @return mixed   array of recipeint, headers,body or Pear_Error
+     * @access public
+     * @author Alan Knowles <alan@akbkhome.com>
+     */
+    function getSendArray()
+    {
+        // prevent warning if this is not set
+        $this->_decode_headers = FALSE;
+        $headerlist =$this->_parseHeaders($this->_header);
+        $to = "";
+        if (!$headerlist) {
+            return $this->raiseError("Message did not contain headers");
+        }
+        foreach($headerlist as $item) {
+            $header[$item['name']] = $item['value'];
+            switch (strtolower($item['name'])) {
+                case "to":
+                case "cc":
+                case "bcc":
+                    $to = ",".$item['value'];
+                default:
+                   break;
+            }
+        }
+        if ($to == "") {
+            return $this->raiseError("Message did not contain any recipents");
+        }
+        $to = substr($to,1);
+        return array($to,$header,$this->_body);
+    } 
+
+    /**
+     * Returns a xml copy of the output of
+     * Mail_mimeDecode::decode. Pass the output in as the
+     * argument. This function can be called statically. Eg:
+     *
+     * $output = $obj->decode();
+     * $xml    = Mail_mimeDecode::getXML($output);
+     *
+     * The DTD used for this should have been in the package. Or
+     * alternatively you can get it from cvs, or here:
+     * http://www.phpguru.org/xmail/xmail.dtd.
+     *
+     * @param  object Input to convert to xml. This should be the
+     *                output of the Mail_mimeDecode::decode function
+     * @return string XML version of input
+     * @access public
+     */
+    function getXML($input)
+    {
+        $crlf    =  "\r\n";
+        $output  = '<?xml version=\'1.0\'?>' . $crlf .
+                   '<!DOCTYPE email SYSTEM "http://www.phpguru.org/xmail/xmail.dtd">' . $crlf .
+                   '<email>' . $crlf .
+                   Mail_mimeDecode::_getXML($input) .
+                   '</email>';
+
+        return $output;
+    }
+
+    /**
+     * Function that does the actual conversion to xml. Does a single
+     * mimepart at a time.
+     *
+     * @param  object  Input to convert to xml. This is a mimepart object.
+     *                 It may or may not contain subparts.
+     * @param  integer Number of tabs to indent
+     * @return string  XML version of input
+     * @access private
+     */
+    function _getXML($input, $indent = 1)
+    {
+        $htab    =  "\t";
+        $crlf    =  "\r\n";
+        $output  =  '';
+        $headers = @(array)$input->headers;
+
+        foreach ($headers as $hdr_name => $hdr_value) {
+
+            // Multiple headers with this name
+            if (is_array($headers[$hdr_name])) {
+                for ($i = 0; $i < count($hdr_value); $i++) {
+                    $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value[$i], $indent);
+                }
+
+            // Only one header of this sort
+            } else {
+                $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value, $indent);
+            }
+        }
+
+        if (!empty($input->parts)) {
+            for ($i = 0; $i < count($input->parts); $i++) {
+                $output .= $crlf . str_repeat($htab, $indent) . '<mimepart>' . $crlf .
+                           Mail_mimeDecode::_getXML($input->parts[$i], $indent+1) .
+                           str_repeat($htab, $indent) . '</mimepart>' . $crlf;
+            }
+        } elseif (isset($input->body)) {
+            $output .= $crlf . str_repeat($htab, $indent) . '<body><![CDATA[' .
+                       $input->body . ']]></body>' . $crlf;
+        }
+
+        return $output;
+    }
+
+    /**
+     * Helper function to _getXML(). Returns xml of a header.
+     *
+     * @param  string  Name of header
+     * @param  string  Value of header
+     * @param  integer Number of tabs to indent
+     * @return string  XML version of input
+     * @access private
+     */
+    function _getXML_helper($hdr_name, $hdr_value, $indent)
+    {
+        $htab   = "\t";
+        $crlf   = "\r\n";
+        $return = '';
+
+        $new_hdr_value = ($hdr_name != 'received') ? Mail_mimeDecode::_parseHeaderValue($hdr_value) : array('value' => $hdr_value);
+        $new_hdr_name  = str_replace(' ', '-', ucwords(str_replace('-', ' ', $hdr_name)));
+
+        // Sort out any parameters
+        if (!empty($new_hdr_value['other'])) {
+            foreach ($new_hdr_value['other'] as $paramname => $paramvalue) {
+                $params[] = str_repeat($htab, $indent) . $htab . '<parameter>' . $crlf .
+                            str_repeat($htab, $indent) . $htab . $htab . '<paramname>' . htmlspecialchars($paramname) . '</paramname>' . $crlf .
+                            str_repeat($htab, $indent) . $htab . $htab . '<paramvalue>' . htmlspecialchars($paramvalue) . '</paramvalue>' . $crlf .
+                            str_repeat($htab, $indent) . $htab . '</parameter>' . $crlf;
+            }
+
+            $params = implode('', $params);
+        } else {
+            $params = '';
+        }
+
+        $return = str_repeat($htab, $indent) . '<header>' . $crlf .
+                  str_repeat($htab, $indent) . $htab . '<headername>' . htmlspecialchars($new_hdr_name) . '</headername>' . $crlf .
+                  str_repeat($htab, $indent) . $htab . '<headervalue>' . htmlspecialchars($new_hdr_value['value']) . '</headervalue>' . $crlf .
+                  $params .
+                  str_repeat($htab, $indent) . '</header>' . $crlf;
+
+        return $return;
+    }
+
+} // End of class
+?>
Index: branches/comu/data/module/Mail/mimePart.php
===================================================================
--- branches/comu/data/module/Mail/mimePart.php	(revision 11984)
+++ branches/comu/data/module/Mail/mimePart.php	(revision 11984)
@@ -0,0 +1,351 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003  Richard Heyes                                     |
+// | All rights reserved.                                                  |
+// |                                                                       |
+// | Redistribution and use in source and binary forms, with or without    |
+// | modification, are permitted provided that the following conditions    |
+// | are met:                                                              |
+// |                                                                       |
+// | o Redistributions of source code must retain the above copyright      |
+// |   notice, this list of conditions and the following disclaimer.       |
+// | o Redistributions in binary form must reproduce the above copyright   |
+// |   notice, this list of conditions and the following disclaimer in the |
+// |   documentation and/or other materials provided with the distribution.|
+// | o The names of the authors may not be used to endorse or promote      |
+// |   products derived from this software without specific prior written  |
+// |   permission.                                                         |
+// |                                                                       |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
+// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
+// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
+// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
+// |                                                                       |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard@phpguru.org>                           |
+// +-----------------------------------------------------------------------+
+
+/**
+*
+*  Raw mime encoding class
+*
+* What is it?
+*   This class enables you to manipulate and build
+*   a mime email from the ground up.
+*
+* Why use this instead of mime.php?
+*   mime.php is a userfriendly api to this class for
+*   people who aren't interested in the internals of
+*   mime mail. This class however allows full control
+*   over the email.
+*
+* Eg.
+*
+* // Since multipart/mixed has no real body, (the body is
+* // the subpart), we set the body argument to blank.
+*
+* $params['content_type'] = 'multipart/mixed';
+* $email = new Mail_mimePart('', $params);
+*
+* // Here we add a text part to the multipart we have
+* // already. Assume $body contains plain text.
+*
+* $params['content_type'] = 'text/plain';
+* $params['encoding']     = '7bit';
+* $text = $email->addSubPart($body, $params);
+*
+* // Now add an attachment. Assume $attach is
+* the contents of the attachment
+*
+* $params['content_type'] = 'application/zip';
+* $params['encoding']     = 'base64';
+* $params['disposition']  = 'attachment';
+* $params['dfilename']    = 'example.zip';
+* $attach =& $email->addSubPart($body, $params);
+*
+* // Now build the email. Note that the encode
+* // function returns an associative array containing two
+* // elements, body and headers. You will need to add extra
+* // headers, (eg. Mime-Version) before sending.
+*
+* $email = $message->encode();
+* $email['headers'][] = 'Mime-Version: 1.0';
+*
+*
+* Further examples are available at http://www.phpguru.org
+*
+* TODO:
+*  - Set encode() to return the $obj->encoded if encode()
+*    has already been run. Unless a flag is passed to specifically
+*    re-build the message.
+*
+* @author  Richard Heyes <richard@phpguru.org>
+* @version $Revision: 1.13 $
+* @package Mail
+*/
+
+class Mail_mimePart {
+
+   /**
+    * The encoding type of this part
+    * @var string
+    */
+    var $_encoding;
+
+   /**
+    * An array of subparts
+    * @var array
+    */
+    var $_subparts;
+
+   /**
+    * The output of this part after being built
+    * @var string
+    */
+    var $_encoded;
+
+   /**
+    * Headers for this part
+    * @var array
+    */
+    var $_headers;
+
+   /**
+    * The body of this part (not encoded)
+    * @var string
+    */
+    var $_body;
+
+    /**
+     * Constructor.
+     *
+     * Sets up the object.
+     *
+     * @param $body   - The body of the mime part if any.
+     * @param $params - An associative array of parameters:
+     *                  content_type - The content type for this part eg multipart/mixed
+     *                  encoding     - The encoding to use, 7bit, 8bit, base64, or quoted-printable
+     *                  cid          - Content ID to apply
+     *                  disposition  - Content disposition, inline or attachment
+     *                  dfilename    - Optional filename parameter for content disposition
+     *                  description  - Content description
+     *                  charset      - Character set to use
+     * @access public
+     */
+    function Mail_mimePart($body = '', $params = array())
+    {
+        if (!defined('MAIL_MIMEPART_CRLF')) {
+            define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE);
+        }
+
+        foreach ($params as $key => $value) {
+            switch ($key) {
+                case 'content_type':
+                    $headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : '');
+                    break;
+
+                case 'encoding':
+                    $this->_encoding = $value;
+                    $headers['Content-Transfer-Encoding'] = $value;
+                    break;
+
+                case 'cid':
+                    $headers['Content-ID'] = '<' . $value . '>';
+                    break;
+
+                case 'disposition':
+                    $headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : '');
+                    break;
+
+                case 'dfilename':
+                    if (isset($headers['Content-Disposition'])) {
+                        $headers['Content-Disposition'] .= '; filename="' . $value . '"';
+                    } else {
+                        $dfilename = $value;
+                    }
+                    break;
+
+                case 'description':
+                    $headers['Content-Description'] = $value;
+                    break;
+
+                case 'charset':
+                    if (isset($headers['Content-Type'])) {
+                        $headers['Content-Type'] .= '; charset="' . $value . '"';
+                    } else {
+                        $charset = $value;
+                    }
+                    break;
+            }
+        }
+
+        // Default content-type
+        if (!isset($headers['Content-Type'])) {
+            $headers['Content-Type'] = 'text/plain';
+        }
+
+        //Default encoding
+        if (!isset($this->_encoding)) {
+            $this->_encoding = '7bit';
+        }
+
+        // Assign stuff to member variables
+        $this->_encoded  = array();
+        $this->_headers  = $headers;
+        $this->_body     = $body;
+    }
+
+    /**
+     * encode()
+     *
+     * Encodes and returns the email. Also stores
+     * it in the encoded member variable
+     *
+     * @return An associative array containing two elements,
+     *         body and headers. The headers element is itself
+     *         an indexed array.
+     * @access public
+     */
+    function encode()
+    {
+        $encoded =& $this->_encoded;
+
+        if (!empty($this->_subparts)) {
+            srand((double)microtime()*1000000);
+            $boundary = '=_' . md5(rand() . microtime());
+            $this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"';
+
+            // Add body parts to $subparts
+            for ($i = 0; $i < count($this->_subparts); $i++) {
+                $headers = array();
+                $tmp = $this->_subparts[$i]->encode();
+                foreach ($tmp['headers'] as $key => $value) {
+                    $headers[] = $key . ': ' . $value;
+                }
+                $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body'];
+            }
+
+            $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF .
+                               implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) .
+                               '--' . $boundary.'--' . MAIL_MIMEPART_CRLF;
+
+        } else {
+            $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF;
+        }
+
+        // Add headers to $encoded
+        $encoded['headers'] =& $this->_headers;
+
+        return $encoded;
+    }
+
+    /**
+     * &addSubPart()
+     *
+     * Adds a subpart to current mime part and returns
+     * a reference to it
+     *
+     * @param $body   The body of the subpart, if any.
+     * @param $params The parameters for the subpart, same
+     *                as the $params argument for constructor.
+     * @return A reference to the part you just added. It is
+     *         crucial if using multipart/* in your subparts that
+     *         you use =& in your script when calling this function,
+     *         otherwise you will not be able to add further subparts.
+     * @access public
+     */
+    function &addSubPart($body, $params)
+    {
+        $this->_subparts[] = new Mail_mimePart($body, $params);
+        return $this->_subparts[count($this->_subparts) - 1];
+    }
+
+    /**
+     * _getEncodedData()
+     *
+     * Returns encoded data based upon encoding passed to it
+     *
+     * @param $data     The data to encode.
+     * @param $encoding The encoding type to use, 7bit, base64,
+     *                  or quoted-printable.
+     * @access private
+     */
+    function _getEncodedData($data, $encoding)
+    {
+        switch ($encoding) {
+            case '8bit':
+            case '7bit':
+                return $data;
+                break;
+
+            case 'quoted-printable':
+                return $this->_quotedPrintableEncode($data);
+                break;
+
+            case 'base64':
+                return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF));
+                break;
+
+            default:
+                return $data;
+        }
+    }
+
+    /**
+     * quoteadPrintableEncode()
+     *
+     * Encodes data to quoted-printable standard.
+     *
+     * @param $input    The data to encode
+     * @param $line_max Optional max line length. Should
+     *                  not be more than 76 chars
+     *
+     * @access private
+     */
+    function _quotedPrintableEncode($input , $line_max = 76)
+    {
+        $lines  = preg_split("/\r?\n/", $input);
+        $eol    = MAIL_MIMEPART_CRLF;
+        $escape = '=';
+        $output = '';
+
+        while(list(, $line) = each($lines)){
+
+            $linlen     = strlen($line);
+            $newline = '';
+
+            for ($i = 0; $i < $linlen; $i++) {
+                $char = substr($line, $i, 1);
+                $dec  = ord($char);
+
+                if (($dec == 32) AND ($i == ($linlen - 1))){    // convert space at eol only
+                    $char = '=20';
+
+                } elseif(($dec == 9) AND ($i == ($linlen - 1))) {  // convert tab at eol only
+                    $char = '=09';
+                } elseif($dec == 9) {
+                    ; // Do nothing if a tab.
+                } elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) {
+                    $char = $escape . strtoupper(sprintf('%02s', dechex($dec)));
+                }
+
+                if ((strlen($newline) + strlen($char)) >= $line_max) {        // MAIL_MIMEPART_CRLF is not counted
+                    $output  .= $newline . $escape . $eol;                    // soft line break; " =\r\n" is okay
+                    $newline  = '';
+                }
+                $newline .= $char;
+            } // end of for
+            $output .= $newline . $eol;
+        }
+        $output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf
+        return $output;
+    }
+} // End of class
+?>
Index: branches/comu/data/module/Mail/mime.php
===================================================================
--- branches/comu/data/module/Mail/mime.php	(revision 11984)
+++ branches/comu/data/module/Mail/mime.php	(revision 11984)
@@ -0,0 +1,713 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003  Richard Heyes                                |
+// | Copyright (c) 2003-2005  The PHP Group                                |
+// | All rights reserved.                                                  |
+// |                                                                       |
+// | Redistribution and use in source and binary forms, with or without    |
+// | modification, are permitted provided that the following conditions    |
+// | are met:                                                              |
+// |                                                                       |
+// | o Redistributions of source code must retain the above copyright      |
+// |   notice, this list of conditions and the following disclaimer.       |
+// | o Redistributions in binary form must reproduce the above copyright   |
+// |   notice, this list of conditions and the following disclaimer in the |
+// |   documentation and/or other materials provided with the distribution.|
+// | o The names of the authors may not be used to endorse or promote      |
+// |   products derived from this software without specific prior written  |
+// |   permission.                                                         |
+// |                                                                       |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
+// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
+// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
+// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
+// |                                                                       |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard@phpguru.org>                           |
+// |         Tomas V.V.Cox <cox@idecnet.com> (port to PEAR)                |
+// +-----------------------------------------------------------------------+
+//
+// $Id: mime.php,v 1.39 2005/06/13 21:24:16 cipri Exp $
+
+require_once(dirname(__FILE__) . '/../PEAR.php');
+require_once(dirname(__FILE__) . '/mimePart.php');
+
+/**
+ * Mime mail composer class. Can handle: text and html bodies, embedded html
+ * images and attachments.
+ * Documentation and examples of this class are avaible here:
+ * http://pear.php.net/manual/
+ *
+ * @notes This class is based on HTML Mime Mail class from
+ *   Richard Heyes <richard@phpguru.org> which was based also
+ *   in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it> and
+ *   Sascha Schumann <sascha@schumann.cx>
+ *
+ * @author   Richard Heyes <richard.heyes@heyes-computing.net>
+ * @author   Tomas V.V.Cox <cox@idecnet.com>
+ * @package  Mail
+ * @access   public
+ */
+class Mail_mime
+{
+    /**
+     * Contains the plain text part of the email
+     * @var string
+     */
+    var $_txtbody;
+    /**
+     * Contains the html part of the email
+     * @var string
+     */
+    var $_htmlbody;
+    /**
+     * contains the mime encoded text
+     * @var string
+     */
+    var $_mime;
+    /**
+     * contains the multipart content
+     * @var string
+     */
+    var $_multipart;
+    /**
+     * list of the attached images
+     * @var array
+     */
+    var $_html_images = array();
+    /**
+     * list of the attachements
+     * @var array
+     */
+    var $_parts = array();
+    /**
+     * Build parameters
+     * @var array
+     */
+    var $_build_params = array();
+    /**
+     * Headers for the mail
+     * @var array
+     */
+    var $_headers = array();
+    /**
+     * End Of Line sequence (for serialize)
+     * @var string
+     */
+    var $_eol;
+
+
+    /**
+     * Constructor function
+     *
+     * @access public
+     */
+    function Mail_mime($crlf = "\r\n")
+    {
+        $this->_setEOL($crlf);
+        $this->_build_params = array(
+                                     'text_encoding' => '7bit',
+                                     'html_encoding' => 'quoted-printable',
+                                     '7bit_wrap'     => 998,
+                                     'html_charset'  => 'ISO-8859-1',
+                                     'text_charset'  => 'ISO-8859-1',
+                                     'head_charset'  => 'ISO-8859-1'
+                                    );
+    }
+
+    /**
+     * Wakeup (unserialize) - re-sets EOL constant
+     *
+     * @access private
+     */
+    function __wakeup()
+    {
+        $this->_setEOL($this->_eol);
+    }
+
+    /**
+     * Accessor function to set the body text. Body text is used if
+     * it's not an html mail being sent or else is used to fill the
+     * text/plain part that emails clients who don't support
+     * html should show.
+     *
+     * @param  string  $data   Either a string or
+     *                         the file name with the contents
+     * @param  bool    $isfile If true the first param should be treated
+     *                         as a file name, else as a string (default)
+     * @param  bool    $append If true the text or file is appended to
+     *                         the existing body, else the old body is
+     *                         overwritten
+     * @return mixed   true on success or PEAR_Error object
+     * @access public
+     */
+    function setTXTBody($data, $isfile = false, $append = false)
+    {
+        if (!$isfile) {
+            if (!$append) {
+                $this->_txtbody = $data;
+            } else {
+                $this->_txtbody .= $data;
+            }
+        } else {
+            $cont = $this->_file2str($data);
+            if (PEAR::isError($cont)) {
+                return $cont;
+            }
+            if (!$append) {
+                $this->_txtbody = $cont;
+            } else {
+                $this->_txtbody .= $cont;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Adds a html part to the mail
+     *
+     * @param  string  $data   Either a string or the file name with the
+     *                         contents
+     * @param  bool    $isfile If true the first param should be treated
+     *                         as a file name, else as a string (default)
+     * @return mixed   true on success or PEAR_Error object
+     * @access public
+     */
+    function setHTMLBody($data, $isfile = false)
+    {
+        if (!$isfile) {
+            $this->_htmlbody = $data;
+        } else {
+            $cont = $this->_file2str($data);
+            if (PEAR::isError($cont)) {
+                return $cont;
+            }
+            $this->_htmlbody = $cont;
+        }
+
+        return true;
+    }
+
+    /**
+     * Adds an image to the list of embedded images.
+     *
+     * @param  string  $file       The image file name OR image data itself
+     * @param  string  $c_type     The content type
+     * @param  string  $name       The filename of the image.
+     *                             Only use if $file is the image data
+     * @param  bool    $isfilename Whether $file is a filename or not
+     *                             Defaults to true
+     * @return mixed   true on success or PEAR_Error object
+     * @access public
+     */
+    function addHTMLImage($file, $c_type='application/octet-stream',
+                          $name = '', $isfilename = true)
+    {
+        $filedata = ($isfilename === true) ? $this->_file2str($file)
+                                           : $file;
+        if ($isfilename === true) {
+            $filename = ($name == '' ? basename($file) : basename($name));
+        } else {
+            $filename = basename($name);
+        }
+        if (PEAR::isError($filedata)) {
+            return $filedata;
+        }
+        $this->_html_images[] = array(
+                                      'body'   => $filedata,
+                                      'name'   => $filename,
+                                      'c_type' => $c_type,
+                                      'cid'    => md5(uniqid(time()))
+                                     );
+        return true;
+    }
+
+    /**
+     * Adds a file to the list of attachments.
+     *
+     * @param  string  $file       The file name of the file to attach
+     *                             OR the file data itself
+     * @param  string  $c_type     The content type
+     * @param  string  $name       The filename of the attachment
+     *                             Only use if $file is the file data
+     * @param  bool    $isFilename Whether $file is a filename or not
+     *                             Defaults to true
+     * @return mixed true on success or PEAR_Error object
+     * @access public
+     */
+    function addAttachment($file, $c_type = 'application/octet-stream',
+                           $name = '', $isfilename = true,
+                           $encoding = 'base64')
+    {
+        $filedata = ($isfilename === true) ? $this->_file2str($file)
+                                           : $file;
+        if ($isfilename === true) {
+            // Force the name the user supplied, otherwise use $file
+            $filename = (!empty($name)) ? $name : $file;
+        } else {
+            $filename = $name;
+        }
+        if (empty($filename)) {
+            return PEAR::raiseError(
+              'The supplied filename for the attachment can\'t be empty'
+            );
+        }
+        $filename = basename($filename);
+        if (PEAR::isError($filedata)) {
+            return $filedata;
+        }
+
+        $this->_parts[] = array(
+                                'body'     => $filedata,
+                                'name'     => $filename,
+                                'c_type'   => $c_type,
+                                'encoding' => $encoding
+                               );
+        return true;
+    }
+
+    /**
+     * Get the contents of the given file name as string
+     *
+     * @param  string  $file_name  path of file to process
+     * @return string  contents of $file_name
+     * @access private
+     */
+    function &_file2str($file_name)
+    {
+        if (!is_readable($file_name)) {
+            return PEAR::raiseError('File is not readable ' . $file_name);
+        }
+        if (!$fd = fopen($file_name, 'rb')) {
+            return PEAR::raiseError('Could not open ' . $file_name);
+        }
+        $filesize = filesize($file_name);
+        if ($filesize == 0){
+            $cont =  "";
+        }else{
+            $cont = fread($fd, $filesize);
+        }
+        fclose($fd);
+        return $cont;
+    }
+
+    /**
+     * Adds a text subpart to the mimePart object and
+     * returns it during the build process.
+     *
+     * @param mixed    The object to add the part to, or
+     *                 null if a new object is to be created.
+     * @param string   The text to add.
+     * @return object  The text mimePart object
+     * @access private
+     */
+    function &_addTextPart(&$obj, $text)
+    {
+        $params['content_type'] = 'text/plain';
+        $params['encoding']     = $this->_build_params['text_encoding'];
+        $params['charset']      = $this->_build_params['text_charset'];
+        if (is_object($obj)) {
+            return $obj->addSubpart($text, $params);
+        } else {
+            return new Mail_mimePart($text, $params);
+        }
+    }
+
+    /**
+     * Adds a html subpart to the mimePart object and
+     * returns it during the build process.
+     *
+     * @param  mixed   The object to add the part to, or
+     *                 null if a new object is to be created.
+     * @return object  The html mimePart object
+     * @access private
+     */
+    function &_addHtmlPart(&$obj)
+    {
+        $params['content_type'] = 'text/html';
+        $params['encoding']     = $this->_build_params['html_encoding'];
+        $params['charset']      = $this->_build_params['html_charset'];
+        if (is_object($obj)) {
+            return $obj->addSubpart($this->_htmlbody, $params);
+        } else {
+            return new Mail_mimePart($this->_htmlbody, $params);
+        }
+    }
+
+    /**
+     * Creates a new mimePart object, using multipart/mixed as
+     * the initial content-type and returns it during the
+     * build process.
+     *
+     * @return object  The multipart/mixed mimePart object
+     * @access private
+     */
+    function &_addMixedPart()
+    {
+        $params['content_type'] = 'multipart/mixed';
+        return new Mail_mimePart('', $params);
+    }
+
+    /**
+     * Adds a multipart/alternative part to a mimePart
+     * object (or creates one), and returns it during
+     * the build process.
+     *
+     * @param  mixed   The object to add the part to, or
+     *                 null if a new object is to be created.
+     * @return object  The multipart/mixed mimePart object
+     * @access private
+     */
+    function &_addAlternativePart(&$obj)
+    {
+        $params['content_type'] = 'multipart/alternative';
+        if (is_object($obj)) {
+            return $obj->addSubpart('', $params);
+        } else {
+            return new Mail_mimePart('', $params);
+        }
+    }
+
+    /**
+     * Adds a multipart/related part to a mimePart
+     * object (or creates one), and returns it during
+     * the build process.
+     *
+     * @param mixed    The object to add the part to, or
+     *                 null if a new object is to be created
+     * @return object  The multipart/mixed mimePart object
+     * @access private
+     */
+    function &_addRelatedPart(&$obj)
+    {
+        $params['content_type'] = 'multipart/related';
+        if (is_object($obj)) {
+            return $obj->addSubpart('', $params);
+        } else {
+            return new Mail_mimePart('', $params);
+        }
+    }
+
+    /**
+     * Adds an html image subpart to a mimePart object
+     * and returns it during the build process.
+     *
+     * @param  object  The mimePart to add the image to
+     * @param  array   The image information
+     * @return object  The image mimePart object
+     * @access private
+     */
+    function &_addHtmlImagePart(&$obj, $value)
+    {
+        $params['content_type'] = $value['c_type'];
+        $params['encoding']     = 'base64';
+        $params['disposition']  = 'inline';
+        $params['dfilename']    = $value['name'];
+        $params['cid']          = $value['cid'];
+        $obj->addSubpart($value['body'], $params);
+    }
+
+    /**
+     * Adds an attachment subpart to a mimePart object
+     * and returns it during the build process.
+     *
+     * @param  object  The mimePart to add the image to
+     * @param  array   The attachment information
+     * @return object  The image mimePart object
+     * @access private
+     */
+    function &_addAttachmentPart(&$obj, $value)
+    {
+        $params['content_type'] = $value['c_type'];
+        $params['encoding']     = $value['encoding'];
+        $params['disposition']  = 'attachment';
+        $params['dfilename']    = $value['name'];
+        $obj->addSubpart($value['body'], $params);
+    }
+
+    /**
+     * Builds the multipart message from the list ($this->_parts) and
+     * returns the mime content.
+     *
+     * @param  array  Build parameters that change the way the email
+     *                is built. Should be associative. Can contain:
+     *                text_encoding  -  What encoding to use for plain text
+     *                                  Default is 7bit
+     *                html_encoding  -  What encoding to use for html
+     *                                  Default is quoted-printable
+     *                7bit_wrap      -  Number of characters before text is
+     *                                  wrapped in 7bit encoding
+     *                                  Default is 998
+     *                html_charset   -  The character set to use for html.
+     *                                  Default is iso-8859-1
+     *                text_charset   -  The character set to use for text.
+     *                                  Default is iso-8859-1
+     *                head_charset   -  The character set to use for headers.
+     *                                  Default is iso-8859-1
+     * @return string The mime content
+     * @access public
+     */
+    function &get($build_params = null)
+    {
+        if (isset($build_params)) {
+            while (list($key, $value) = each($build_params)) {
+                $this->_build_params[$key] = $value;
+            }
+        }
+
+        if (!empty($this->_html_images) AND isset($this->_htmlbody)) {
+            foreach ($this->_html_images as $value) {
+                $regex = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' . preg_quote($value['name'], '#') .
+                         '\3#';
+                $rep = '\1\2=\3cid:' . $value['cid'] .'\3';
+                $this->_htmlbody = preg_replace($regex, $rep,
+                                       $this->_htmlbody
+                                   );
+            }
+        }
+
+        $null        = null;
+        $attachments = !empty($this->_parts)                ? true : false;
+        $html_images = !empty($this->_html_images)          ? true : false;
+        $html        = !empty($this->_htmlbody)             ? true : false;
+        $text        = (!$html AND !empty($this->_txtbody)) ? true : false;
+
+        switch (true) {
+        case $text AND !$attachments:
+            $message =& $this->_addTextPart($null, $this->_txtbody);
+            break;
+
+        case !$text AND !$html AND $attachments:
+            $message =& $this->_addMixedPart();
+            for ($i = 0; $i < count($this->_parts); $i++) {
+                $this->_addAttachmentPart($message, $this->_parts[$i]);
+            }
+            break;
+
+        case $text AND $attachments:
+            $message =& $this->_addMixedPart();
+            $this->_addTextPart($message, $this->_txtbody);
+            for ($i = 0; $i < count($this->_parts); $i++) {
+                $this->_addAttachmentPart($message, $this->_parts[$i]);
+            }
+            break;
+
+        case $html AND !$attachments AND !$html_images:
+            if (isset($this->_txtbody)) {
+                $message =& $this->_addAlternativePart($null);
+                $this->_addTextPart($message, $this->_txtbody);
+                $this->_addHtmlPart($message);
+            } else {
+                $message =& $this->_addHtmlPart($null);
+            }
+            break;
+
+        case $html AND !$attachments AND $html_images:
+            if (isset($this->_txtbody)) {
+                $message =& $this->_addAlternativePart($null);
+                $this->_addTextPart($message, $this->_txtbody);
+                $related =& $this->_addRelatedPart($message);
+            } else {
+                $message =& $this->_addRelatedPart($null);
+                $related =& $message;
+            }
+            $this->_addHtmlPart($related);
+            for ($i = 0; $i < count($this->_html_images); $i++) {
+                $this->_addHtmlImagePart($related, $this->_html_images[$i]);
+            }
+            break;
+
+        case $html AND $attachments AND !$html_images:
+            $message =& $this->_addMixedPart();
+            if (isset($this->_txtbody)) {
+                $alt =& $this->_addAlternativePart($message);
+                $this->_addTextPart($alt, $this->_txtbody);
+                $this->_addHtmlPart($alt);
+            } else {
+                $this->_addHtmlPart($message);
+            }
+            for ($i = 0; $i < count($this->_parts); $i++) {
+                $this->_addAttachmentPart($message, $this->_parts[$i]);
+            }
+            break;
+
+        case $html AND $attachments AND $html_images:
+            $message =& $this->_addMixedPart();
+            if (isset($this->_txtbody)) {
+                $alt =& $this->_addAlternativePart($message);
+                $this->_addTextPart($alt, $this->_txtbody);
+                $rel =& $this->_addRelatedPart($alt);
+            } else {
+                $rel =& $this->_addRelatedPart($message);
+            }
+            $this->_addHtmlPart($rel);
+            for ($i = 0; $i < count($this->_html_images); $i++) {
+                $this->_addHtmlImagePart($rel, $this->_html_images[$i]);
+            }
+            for ($i = 0; $i < count($this->_parts); $i++) {
+                $this->_addAttachmentPart($message, $this->_parts[$i]);
+            }
+            break;
+
+        }
+
+        if (isset($message)) {
+            $output = $message->encode();
+            $this->_headers = array_merge($this->_headers,
+                                          $output['headers']);
+            return $output['body'];
+
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns an array with the headers needed to prepend to the email
+     * (MIME-Version and Content-Type). Format of argument is:
+     * $array['header-name'] = 'header-value';
+     *
+     * @param  array $xtra_headers Assoc array with any extra headers.
+     *                             Optional.
+     * @return array Assoc array with the mime headers
+     * @access public
+     */
+    function &headers($xtra_headers = null)
+    {
+        // Content-Type header should already be present,
+        // So just add mime version header
+        $headers['MIME-Version'] = '1.0';
+        if (isset($xtra_headers)) {
+            $headers = array_merge($headers, $xtra_headers);
+        }
+        $this->_headers = array_merge($headers, $this->_headers);
+
+        return $this->_encodeHeaders($this->_headers);
+    }
+
+    /**
+     * Get the text version of the headers
+     * (usefull if you want to use the PHP mail() function)
+     *
+     * @param  array   $xtra_headers Assoc array with any extra headers.
+     *                               Optional.
+     * @return string  Plain text headers
+     * @access public
+     */
+    function txtHeaders($xtra_headers = null)
+    {
+        $headers = $this->headers($xtra_headers);
+        $ret = '';
+        foreach ($headers as $key => $val) {
+            $ret .= "$key: $val" . MAIL_MIME_CRLF;
+        }
+        return $ret;
+    }
+
+    /**
+     * Sets the Subject header
+     *
+     * @param  string $subject String to set the subject to
+     * access  public
+     */
+    function setSubject($subject)
+    {
+        $this->_headers['Subject'] = $subject;
+    }
+
+    /**
+     * Set an email to the From (the sender) header
+     *
+     * @param  string $email The email direction to add
+     * @access public
+     */
+    function setFrom($email)
+    {
+        $this->_headers['From'] = $email;
+    }
+
+    /**
+     * Add an email to the Cc (carbon copy) header
+     * (multiple calls to this method are allowed)
+     *
+     * @param  string $email The email direction to add
+     * @access public
+     */
+    function addCc($email)
+    {
+        if (isset($this->_headers['Cc'])) {
+            $this->_headers['Cc'] .= ", $email";
+        } else {
+            $this->_headers['Cc'] = $email;
+        }
+    }
+
+    /**
+     * Add an email to the Bcc (blank carbon copy) header
+     * (multiple calls to this method are allowed)
+     *
+     * @param  string $email The email direction to add
+     * @access public
+     */
+    function addBcc($email)
+    {
+        if (isset($this->_headers['Bcc'])) {
+            $this->_headers['Bcc'] .= ", $email";
+        } else {
+            $this->_headers['Bcc'] = $email;
+        }
+    }
+
+    /**
+     * Encodes a header as per RFC2047
+     *
+     * @param  string  $input The header data to encode
+     * @return string  Encoded data
+     * @access private
+     */
+    function _encodeHeaders($input)
+    {
+        foreach ($input as $hdr_name => $hdr_value) {
+            preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $hdr_value, $matches);
+            foreach ($matches[1] as $value) {
+                $replacement = preg_replace('/([\x80-\xFF])/e',
+                                            '"=" .
+                                            strtoupper(dechex(ord("\1")))',
+                                            $value);
+                $hdr_value = str_replace($value, '=?' .
+                                         $this->_build_params['head_charset'] .
+                                         '?Q?' . $replacement . '?=',
+                                         $hdr_value);
+            }
+            $input[$hdr_name] = $hdr_value;
+        }
+
+        return $input;
+    }
+
+    /**
+     * Set the object's end-of-line and define the constant if applicable
+     *
+     * @param string $eol End Of Line sequence
+     * @access private
+     */
+    function _setEOL($eol)
+    {
+        $this->_eol = $eol;
+        if (!defined('MAIL_MIME_CRLF')) {
+            define('MAIL_MIME_CRLF', $this->_eol, true);
+        }
+    }
+
+    
+
+} // End of class
+?>
Index: branches/comu/data/module/Net/UserAgent/Mobile/NonMobile.php
===================================================================
--- branches/comu/data/module/Net/UserAgent/Mobile/NonMobile.php	(revision 11984)
+++ branches/comu/data/module/Net/UserAgent/Mobile/NonMobile.php	(revision 11984)
@@ -0,0 +1,188 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+/**
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id: NonMobile.php,v 1.12 2007/02/20 15:20:02 kuboa Exp $
+ * @see        Net_UserAgent_Mobile_Common
+ * @since      File available since Release 0.1.0
+ */
+
+require_once(dirname(__FILE__) . '/Common.php');
+require_once(dirname(__FILE__) . '/Display.php');
+
+// {{{ Net_UserAgent_Mobile_NonMobile
+
+/**
+ * Non-Mobile Agent implementation
+ *
+ * Net_UserAgent_Mobile_NonMobile is a subclass of
+ * {@link Net_UserAgent_Mobile_Common}, which implements non-mobile or
+ * unimplemented user agents.
+ *
+ * SYNOPSIS:
+ * <code>
+ * require_once 'Net/UserAgent/Mobile.php';
+ *
+ * $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/4.0';
+ * $agent = &Net_UserAgent_Mobile::factory();
+ * </code>
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @see        Net_UserAgent_Mobile_Common
+ * @since      Class available since Release 0.1.0
+ */
+class Net_UserAgent_Mobile_NonMobile extends Net_UserAgent_Mobile_Common
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     */
+
+    // }}}
+    // {{{ isNonMobile()
+
+    /**
+     * returns true
+     *
+     * @return boolean
+     */
+    function isNonMobile()
+    {
+        return true;
+    }
+
+    // }}}
+    // {{{ parse()
+
+    /**
+     * parse HTTP_USER_AGENT string
+     */
+    function parse()
+    {
+        @list($this->name, $this->version) =
+            explode('/', $this->getUserAgent());
+    }
+
+    // }}}
+    // {{{ makeDisplay()
+
+    /**
+     * create a new {@link Net_UserAgent_Mobile_Display} class instance
+     *
+     * @return object a newly created {@link Net_UserAgent_Mobile_Display}
+     *     object
+     * @see Net_UserAgent_Mobile_Display
+     */
+    function makeDisplay()
+    {
+        return new Net_UserAgent_Mobile_Display(null);
+    }
+
+    // }}}
+    // {{{ getModel()
+
+    /**
+     * returns name of the model
+     *
+     * @return string
+     */
+    function getModel()
+    {
+        return '';
+    }
+
+    // }}}
+    // {{{ getDeviceID()
+
+    /**
+     * returns device ID
+     *
+     * @return string
+     */
+    function getDeviceID()
+    {
+        return '';
+    }
+
+    // }}}
+    // {{{ getCarrierShortName()
+
+    /**
+     * returns the short name of the carrier
+     *
+     * @return string
+     */
+    function getCarrierShortName()
+    {
+        return 'N';
+    }
+
+    // }}}
+    // {{{ getCarrierLongName()
+
+    /**
+     * returns the long name of the carrier
+     *
+     * @return string
+     */
+    function getCarrierLongName()
+    {
+        return 'NonMobile';
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+
+/*
+ * Local Variables:
+ * mode: php
+ * coding: iso-8859-1
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * indent-tabs-mode: nil
+ * End:
+ */
+?>
Index: branches/comu/data/module/Net/UserAgent/Mobile/DoCoMoDisplayMap.php
===================================================================
--- branches/comu/data/module/Net/UserAgent/Mobile/DoCoMoDisplayMap.php	(revision 11984)
+++ branches/comu/data/module/Net/UserAgent/Mobile/DoCoMoDisplayMap.php	(revision 11984)
@@ -0,0 +1,1471 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+/**
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id: DoCoMoDisplayMap.php,v 1.32 2007/02/20 18:30:17 kuboa Exp $
+ * @link       http://www.nttdocomo.co.jp/service/imode/make/content/spec/screen_area/index.html
+ * @see        Net_UserAgent_Mobile_Display
+ * @since      File available since Release 0.1
+ */
+
+// {{{ Net_UserAgent_Mobile_DoCoMoDisplayMap
+
+/**
+ * Display information mapping for DoCoMo.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @link       http://www.nttdocomo.co.jp/service/imode/make/content/spec/screen_area/index.html
+ * @see        Net_UserAgent_Mobile_Display
+ * @since      Class available since Release 0.1
+ */
+class Net_UserAgent_Mobile_DoCoMoDisplayMap
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     */
+
+    // }}}
+    // {{{ get()
+
+    /**
+     * Returns the display information of the model.
+     *
+     * @param string $model the name of the model
+     * @return array
+     * @static
+     */
+    function get($model)
+    {
+        static $displayMap;
+        if (!isset($displayMap)) {
+            if (isset($_SERVER['DOCOMO_MAP'])) {
+
+                // using the specified XML data
+                while (true) {
+                    if (!function_exists('xml_parser_create')
+                        || !is_readable($_SERVER['DOCOMO_MAP'])
+                        ) {
+                        break;
+                    }
+                    $xml = file_get_contents($_SERVER['DOCOMO_MAP']);
+                    $parser = xml_parser_create();
+                    if ($parser === false) {
+                        break;
+                    }
+                    xml_parse_into_struct($parser, $xml, $values, $indexes);
+                    if (!xml_parser_free($parser)) {
+                        break;
+                    }
+                    if (isset($indexes['OPT'])) {
+                        unset($indexes['OPT']);
+                    }
+                    foreach ($indexes as $modelName => $modelIndexes) {
+                        $displayMap[$modelName] = array();
+                        foreach ($values[ $modelIndexes[0] ]['attributes'] as $attributeName => $attributeValue) {
+                            $displayMap[$modelName][ strtolower($attributeName) ] = $attributeValue;
+                        }
+                    }
+                    break;
+                }
+            }
+
+            if (!isset($displayMap)) {
+                $displayMap = array(
+
+                                    // i-mode compliant HTML 1.0
+                                    'D501I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 72,
+                                                     'depth'  => 2,
+                                                     'color'  => 0
+                                                     ),
+                                    'F501I' => array(
+                                                     'width'  => 112,
+                                                     'height' => 84,
+                                                     'depth'  => 2,
+                                                     'color'  => 0
+                                                     ),
+                                    'N501I' => array(
+                                                     'width'  => 118,
+                                                     'height' => 128,
+                                                     'depth'  => 2,
+                                                     'color'  => 0
+                                                     ),
+                                    'P501I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 120,
+                                                     'depth'  => 2,
+                                                     'color'  => 0
+                                                     ),
+
+                                    // i-mode compliant HTML 2.0
+                                    'D502I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 90,
+                                                     'depth'  => 256,
+                                                     'color'  => 1
+                                                     ),
+                                    'F502I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 91,
+                                                     'depth'  => 256,
+                                                     'color'  => 1
+                                                     ),
+                                    'N502I' => array(
+                                                     'width'  => 118,
+                                                     'height' => 128,
+                                                     'depth'  => 4,
+                                                     'color'  => 0
+                                                     ),
+                                    'P502I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 117,
+                                                     'depth'  => 4,
+                                                     'color'  => 0
+                                                     ),
+                                    'NM502I' => array(
+                                                      'width'  => 111,
+                                                      'height' => 106,
+                                                      'depth'  => 2,
+                                                      'color'  => 0
+                                                      ),
+                                    'SO502I' => array(
+                                                      'width'  => 120,
+                                                      'height' => 120,
+                                                      'depth'  => 4,
+                                                      'color'  => 0
+                                                      ),
+                                    'F502IT' => array(
+                                                      'width'  => 96,
+                                                      'height' => 91,
+                                                      'depth'  => 256,
+                                                      'color'  => 1
+                                                      ),
+                                    'N502IT' => array(
+                                                      'width'  => 118,
+                                                      'height' => 128,
+                                                      'depth'  => 256,
+                                                      'color'  => 1
+                                                      ),
+                                    'SO502IWM' => array(
+                                                        'width'  => 120,
+                                                        'height' => 113,
+                                                        'depth'  => 256,
+                                                        'color'  => 1
+                                                        ),
+                                    'SH821I' => array(
+                                                      'width'  => 96,
+                                                      'height' => 78,
+                                                      'depth'  => 256,
+                                                      'color'  => 1
+                                                      ),
+                                    'N821I' => array(
+                                                     'width'  => 118,
+                                                     'height' => 128,
+                                                     'depth'  => 4,
+                                                     'color'  => 0
+                                                     ),
+                                    'P821I' => array(
+                                                     'width'  => 118,
+                                                     'height' => 128,
+                                                     'depth'  => 4,
+                                                     'color'  => 0
+                                                     ),
+                                    'D209I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 90,
+                                                     'depth'  => 256,
+                                                     'color'  => 1
+                                                     ),
+                                    'ER209I' => array(
+                                                      'width'  => 120,
+                                                      'height' => 72,
+                                                      'depth'  => 2,
+                                                      'color'  => 0
+                                                      ),
+                                    'F209I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 91,
+                                                     'depth'  => 256,
+                                                     'color'  => 1
+                                                     ),
+                                    'KO209I' => array(
+                                                      'width'  => 96,
+                                                      'height' => 96,
+                                                      'depth'  => 256,
+                                                      'color'  => 1
+                                                      ),
+                                    'N209I' => array(
+                                                     'width'  => 108,
+                                                     'height' => 82,
+                                                     'depth'  => 4,
+                                                     'color'  => 0
+                                                     ),
+                                    'P209I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 87,
+                                                     'depth'  => 4,
+                                                     'color'  => 0
+                                                     ),
+                                    'P209IS' => array(
+                                                      'width'  => 96,
+                                                      'height' => 87,
+                                                      'depth'  => 256,
+                                                      'color'  => 1
+                                                      ),
+                                    'R209I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 72,
+                                                     'depth'  => 4,
+                                                     'color'  => 0
+                                                     ),
+                                    'P651PS' => array(
+                                                      'width'  => 96,
+                                                      'height' => 87,
+                                                      'depth'  => 4,
+                                                      'color'  => 0
+                                                      ),
+                                    'R691I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 72,
+                                                     'depth'  => 4,
+                                                     'color'  => 0
+                                                     ),
+                                    'F671I' => array(
+                                                     'width'  => 120,
+                                                     'height' => 126,
+                                                     'depth'  => 256,
+                                                     'color'  => 1
+                                                     ),
+                                    'F210I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 113,
+                                                     'depth'  => 256,
+                                                     'color'  => 1
+                                                     ),
+                                    'N210I' => array(
+                                                     'width'  => 118,
+                                                     'height' => 113,
+                                                     'depth'  => 256,
+                                                     'color'  => 1
+                                                     ),
+                                    'P210I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 91,
+                                                     'depth'  => 256,
+                                                     'color'  => 1
+                                                     ),
+                                    'KO210I' => array(
+                                                      'width'  => 96,
+                                                      'height' => 96,
+                                                      'depth'  => 256,
+                                                      'color'  => 1
+                                                      ),
+
+                                    // i-mode compliant HTML 3.0
+                                    'F503I' => array(
+                                                     'width'  => 120,
+                                                     'height' => 130,
+                                                     'depth'  => 256,
+                                                     'color'  => 1
+                                                     ),
+                                    'F503IS' => array(
+                                                      'width'  => 120,
+                                                      'height' => 130,
+                                                      'depth'  => 4096,
+                                                      'color'  => 1
+                                                      ),
+                                    'P503I' => array(
+                                                     'width'  => 120,
+                                                     'height' => 130,
+                                                     'depth'  => 256,
+                                                     'color'  => 1
+                                                     ),
+                                    'P503IS' => array(
+                                                      'width'  => 120,
+                                                      'height' => 130,
+                                                      'depth'  => 256,
+                                                      'color'  => 1
+                                                      ),
+                                    'N503I' => array(
+                                                     'width'  => 118,
+                                                     'height' => 128,
+                                                     'depth'  => 4096,
+                                                     'color'  => 1
+                                                     ),
+                                    'N503IS' => array(
+                                                      'width'  => 118,
+                                                      'height' => 128,
+                                                      'depth'  => 4096,
+                                                      'color'  => 1
+                                                      ),
+                                    'SO503I' => array(
+                                                      'width'  => 120,
+                                                      'height' => 113,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'SO503IS' => array(
+                                                       'width'  => 120,
+                                                       'height' => 113,
+                                                       'depth'  => 65536,
+                                                       'color'  => 1
+                                                       ),
+                                    'D503I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 126,
+                                                     'depth'  => 4096,
+                                                     'color'  => 1
+                                                     ),
+                                    'D503IS' => array(
+                                                      'width'  => 132,
+                                                      'height' => 126,
+                                                      'depth'  => 4096,
+                                                      'color'  => 1
+                                                      ),
+                                    'D210I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 91,
+                                                     'depth'  => 256,
+                                                     'color'  => 1
+                                                     ),
+                                    'SO210I' => array(
+                                                      'width'  => 120,
+                                                      'height' => 113,
+                                                      'depth'  => 256,
+                                                      'color'  => 1
+                                                      ),
+                                    'F211I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 113,
+                                                     'depth'  => 4096,
+                                                     'color'  => 1
+                                                     ),
+                                    'D211I' => array(
+                                                     'width'  => 100,
+                                                     'height' => 91,
+                                                     'depth'  => 4096,
+                                                     'color'  => 1
+                                                     ),
+                                    'N211I' => array(
+                                                     'width'  => 118,
+                                                     'height' => 128,
+                                                     'depth'  => 4096,
+                                                     'color'  => 1
+                                                     ),
+                                    'N211IS' => array(
+                                                      'width'  => 118,
+                                                      'height' => 128,
+                                                      'depth'  => 4096,
+                                                      'color'  => 1
+                                                      ),
+                                    'P211I' => array(
+                                                     'width'  => 120,
+                                                     'height' => 130,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'P211IS' => array(
+                                                      'width'  => 120,
+                                                      'height' => 130,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'SO211I' => array(
+                                                      'width'  => 120,
+                                                      'height' => 112,
+                                                      'depth'  => 4096,
+                                                      'color'  => 1
+                                                      ),
+                                    'R211I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 98,
+                                                     'depth'  => 4096,
+                                                     'color'  => 1
+                                                     ),
+                                    'SH251I' => array(
+                                                      'width'  => 120,
+                                                      'height' => 130,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'SH251IS' => array(
+                                                       'width'  => 176,
+                                                       'height' => 187,
+                                                       'depth'  => 65536,
+                                                       'color'  => 1
+                                                       ),
+                                    'R692I' => array(
+                                                     'width'  => 96,
+                                                     'height' => 98,
+                                                     'depth'  => 4096,
+                                                     'color'  => 1
+                                                     ),
+
+                                    // i-mode compliant HTML 3.0
+                                    // (FOMA 2001/2002/2101V)
+                                    'N2001' => array(
+                                                     'width'  => 118,
+                                                     'height' => 128,
+                                                     'depth'  => 4096,
+                                                     'color'  => 1
+                                                     ),
+                                    'N2002' => array(
+                                                     'width'  => 118,
+                                                     'height' => 128,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'P2002' => array(
+                                                     'width'  => 118,
+                                                     'height' => 128,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'D2101V' => array(
+                                                      'width'  => 120,
+                                                      'height' => 130,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'P2101V' => array(
+                                                      'width'  => 163,
+                                                      'height' => 182,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'SH2101V' => array(
+                                                       'width'  => 800,
+                                                       'height' => 600,
+                                                       'depth'  => 65536,
+                                                       'color'  => 1
+                                                       ),
+                                    'T2101V' => array(
+                                                      'width'  => 176,
+                                                      'height' => 144,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+
+                                    // i-mode compliant HTML 4.0
+                                    'D504I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 144,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'F504I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 136,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'F504IS' => array(
+                                                      'width'  => 132,
+                                                      'height' => 136,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'N504I' => array(
+                                                     'width'  => 160,
+                                                     'height' => 180,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'N504IS' => array(
+                                                      'width'  => 160,
+                                                      'height' => 180,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'SO504I' => array(
+                                                      'width'  => 120,
+                                                      'height' => 112,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'P504I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 144,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'P504IS' => array(
+                                                      'width'  => 132,
+                                                      'height' => 144,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'D251I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 144,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'D251IS' => array(
+                                                      'width'  => 132,
+                                                      'height' => 144,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'F251I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 140,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'N251I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 140,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'N251IS' => array(
+                                                      'width'  => 132,
+                                                      'height' => 140,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'P251IS' => array(
+                                                      'width'  => 132,
+                                                      'height' => 144,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'F671IS' => array(
+                                                      'width'  => 160,
+                                                      'height' => 120,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'F212I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 136,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'SO212I' => array(
+                                                      'width'  => 120,
+                                                      'height' => 112,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'F661I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 136,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'F672I' => array(
+                                                     'width'  => 160,
+                                                     'height' => 120,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'SO213I' => array(
+                                                      'width'  => 120,
+                                                      'height' => 112,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'SO213IS' => array(
+                                                       'width'  => 120,
+                                                       'height' => 112,
+                                                       'depth'  => 65536,
+                                                       'color'  => 1
+                                                       ),
+                                    'SO213IWR' => array(
+                                                        'width'  => 120,
+                                                        'height' => 112,
+                                                        'depth'  => 65536,
+                                                        'color'  => 1
+                                                        ),
+
+                                    // i-mode compliant HTML 4.0
+                                    // (FOMA 2051/2102V/2701 etc.)
+                                    'F2051' => array(
+                                                     'width'  => 176,
+                                                     'height' => 182,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'N2051' => array(
+                                                     'width'  => 176,
+                                                     'height' => 198,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'P2102V' => array(
+                                                      'width'  => 176,
+                                                      'height' => 198,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'P2102V' => array(
+                                                      'width'  => 176,
+                                                      'height' => 198,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'F2102V' => array(
+                                                      'width'  => 176,
+                                                      'height' => 182,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'N2102V' => array(
+                                                      'width'  => 176,
+                                                      'height' => 198,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'N2701' => array(
+                                                     'width'  => 176,
+                                                     'height' => 198,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'NM850IG' => array(
+                                                       'width'  => 176,
+                                                       'height' => 144,
+                                                       'depth'  => 65536,
+                                                       'color'  => 1
+                                                       ),
+
+                                    // i-mode compliant HTML 5.0 (505i etc.)
+                                    'D505I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'SO505I' => array(
+                                                      'width'  => 256,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'SH505I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 252,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'N505I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'F505I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 268,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'P505I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 266,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'D505IS' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'P505IS' => array(
+                                                      'width'  => 240,
+                                                      'height' => 266,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'N505IS' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'SO505IS' => array(
+                                                       'width'  => 240,
+                                                       'height' => 256,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'SH505IS' => array(
+                                                       'width'  => 240,
+                                                       'height' => 252,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'F505IGPS' => array(
+                                                        'width'  => 240,
+                                                        'height' => 268,
+                                                        'depth'  => 262144,
+                                                        'color'  => 1
+                                                        ),
+                                    'D252I' => array(
+                                                     'width'  => 176,
+                                                     'height' => 198,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'SH252I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 252,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'P252I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 144,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'N252I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 140,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'P252IS' => array(
+                                                      'width'  => 132,
+                                                      'height' => 144,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'D506I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'F506I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 268,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'N506I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 295,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'P506IC' => array(
+                                                      'width'  => 240,
+                                                      'height' => 266,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'SH506IC' => array(
+                                                       'width'  => 240,
+                                                       'height' => 252,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'SO506IC' => array(
+                                                       'width'  => 240,
+                                                       'height' => 256,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'N506IS' => array(
+                                                      'width'  => 240,
+                                                      'height' => 295,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'SO506I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 256,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'SO506IS' => array(
+                                                       'width'  => 240,
+                                                       'height' => 256,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'N506ISII' => array(
+                                                        'width'  => 240,
+                                                        'height' => 295,
+                                                        'depth'  => 262144,
+                                                        'color'  => 1
+                                                        ),
+                                    'P506ICII' => array(
+                                                        'width'  => 240,
+                                                        'height' => 266,
+                                                        'depth'  => 65536,
+                                                        'color'  => 1
+                                                        ),
+                                    'D253I' => array(
+                                                     'width'  => 176,
+                                                     'height' => 198,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'N253I' => array(
+                                                     'width'  => 160,
+                                                     'height' => 180,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'P253I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 144,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'D253IWM' => array(
+                                                       'width'  => 220,
+                                                       'height' => 144,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'P253IS' => array(
+                                                      'width'  => 132,
+                                                      'height' => 144,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'P213I' => array(
+                                                     'width'  => 132,
+                                                     'height' => 144,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+
+                                    // i-mode compliant HTML 5.0
+                                    // (FOMA 900i etc.)
+                                    'F900I' => array(
+                                                     'width'  => 230,
+                                                     'height' => 240,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'N900I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 269,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'P900I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 266,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'SH900I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 252,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'F900IT' => array(
+                                                      'width'  => 230,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'P900IV' => array(
+                                                      'width'  => 240,
+                                                      'height' => 266,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'N900IS' => array(
+                                                      'width'  => 240,
+                                                      'height' => 269,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'D900I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'F900IC' => array(
+                                                      'width'  => 230,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'F880IES' => array(
+                                                       'width'  => 240,
+                                                       'height' => 256,
+                                                       'depth'  => 65536,
+                                                       'color'  => 1
+                                                       ),
+                                    'N900IL' => array(
+                                                      'width'  => 240,
+                                                      'height' => 269,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'N900IG' => array(
+                                                      'width'  => 240,
+                                                      'height' => 269,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'SH901IC' => array(
+                                                       'width'  => 240,
+                                                       'height' => 252,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'F901IC' => array(
+                                                      'width'  => 230,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'N901IC' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'D901I' => array(
+                                                     'width'  => 230,
+                                                     'height' => 240,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'P901I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'F700I' => array(
+                                                     'width'  => 230,
+                                                     'height' => 240,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'SH700I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 252,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'N700I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'P700I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'F700IS' => array(
+                                                      'width'  => 230,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'SH700IS' => array(
+                                                       'width'  => 240,
+                                                       'height' => 252,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'SA700IS' => array(
+                                                       'width'  => 240,
+                                                       'height' => 252,
+                                                       'depth'  => 65536,
+                                                       'color'  => 1
+                                                       ),
+
+                                    'SH901IS' => array(
+                                                       'width'  => 240,
+                                                       'height' => 252,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'F901IS' => array(
+                                                      'width'  => 230,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'D901IS' => array(
+                                                      'width'  => 230,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'P901IS' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'N901IS' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'P901ITV' => array(
+                                                       'width'  => 240,
+                                                       'height' => 270,
+                                                       'depth'  => 65536,
+                                                       'color'  => 1
+                                                       ),
+                                    'SH851I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 252,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'P851I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'F881IES' => array(
+                                                       'width'  => 240,
+                                                       'height' => 256,
+                                                       'depth'  => 65536,
+                                                       'color'  => 1
+                                                       ),
+                                    'D701I' => array(
+                                                     'width'  => 230,
+                                                     'height' => 240,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'N701I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'P701ID' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'D701IWM' => array(
+                                                       'width'  => 230,
+                                                       'height' => 240,
+                                                       'depth'  => 65536,
+                                                       'color'  => 1
+                                                       ),
+                                    'N701IECO' => array(
+                                                        'width'  => 240,
+                                                        'height' => 270,
+                                                        'depth'  => 65536,
+                                                        'color'  => 1
+                                                        ),
+                                    'SA800I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 252,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'L600I' => array(
+                                                     'width'  => 176,
+                                                     'height' => 189,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'N600I' => array(
+                                                     'width'  => 176,
+                                                     'height' => 180,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'L601I' => array(
+                                                     'width'  => 176,
+                                                     'height' => 189,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'M702IS' => array(
+                                                      'width'  => 240,
+                                                      'height' => 267,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'M702IG' => array(
+                                                      'width'  => 240,
+                                                      'height' => 267,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+
+                                    // i-mode compliant HTML 6.0
+                                    // (FOMA 902i etc.)
+                                    'F902I' => array(
+                                                     'width'  => 230,
+                                                     'height' => 240,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'D902I' => array(
+                                                     'width'  => 230,
+                                                     'height' => 240,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'N902I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'P902I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'SH902I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'SO902I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 256,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'SH902IS' => array(
+                                                       'width'  => 240,
+                                                       'height' => 240,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'P902IS' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'N902IS' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'D902IS' => array(
+                                                      'width'  => 230,
+                                                      'height' => 320,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'F902IS' => array(
+                                                      'width'  => 230,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'SO902IWP+' => array(
+                                                         'width'  => 240,
+                                                         'height' => 256,
+                                                         'depth'  => 262144,
+                                                         'color'  => 1
+                                                         ),
+                                    'SH902ISL' => array(
+                                                        'width'  => 240,
+                                                        'height' => 240,
+                                                        'depth'  => 262144,
+                                                        'color'  => 1
+                                                        ),
+                                    'N902IX' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'N902IL' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'P702I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'N702ID' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'F702ID' => array(
+                                                      'width'  => 230,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'SH702ID' => array(
+                                                       'width'  => 240,
+                                                       'height' => 240,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'D702I' => array(
+                                                     'width'  => 230,
+                                                     'height' => 240,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'SO702I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 256,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'D702IBCL' => array(
+                                                        'width'  => 230,
+                                                        'height' => 240,
+                                                        'depth'  => 262144,
+                                                        'color'  => 1
+                                                        ),
+                                    'SA702I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 252,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'SH702IS' => array(
+                                                       'width'  => 240,
+                                                       'height' => 240,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'N702IS' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 65536,
+                                                      'color'  => 1
+                                                      ),
+                                    'P702ID' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'D702IF' => array(
+                                                      'width'  => 230,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'D851IWM' => array(
+                                                       'width'  => 230,
+                                                       'height' => 320,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'F882IES' => array(
+                                                       'width'  => 240,
+                                                       'height' => 256,
+                                                       'depth'  => 65536,
+                                                       'color'  => 1
+                                                       ),
+                                    'N601I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 65536,
+                                                     'color'  => 1
+                                                     ),
+                                    'D800IDS' => array(
+                                                       'width'  => 230,
+                                                       'height' => 240,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'P703IMYU' => array(
+                                                        'width'  => 240,
+                                                        'height' => 270,
+                                                        'depth'  => 262144,
+                                                        'color'  => 1
+                                                        ),
+
+                                    // i-mode compliant HTML 7.0
+                                    // (FOMA 903i etc.)
+                                    'SH903I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 320,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'P903I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'N903I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'D903I' => array(
+                                                     'width'  => 230,
+                                                     'height' => 320,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'F903I' => array(
+                                                     'width'  => 230,
+                                                     'height' => 240,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'SO903I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 368,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'D903ITV' => array(
+                                                      'width'  => 230,
+                                                      'height' => 320,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'F903IX' => array(
+                                                      'width'  => 230,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'P903ITV' => array(
+                                                       'width'  => 240,
+                                                       'height' => 350,
+                                                       'depth'  => 262144,
+                                                       'color'  => 1
+                                                       ),
+                                    'N703ID' => array(
+                                                      'width'  => 240,
+                                                      'height' => 270,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'F703I' => array(
+                                                     'width'  => 230,
+                                                     'height' => 240,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'P703I' => array(
+                                                     'width'  => 240,
+                                                     'height' => 270,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'D703I' => array(
+                                                     'width'  => 230,
+                                                     'height' => 240,
+                                                     'depth'  => 262144,
+                                                     'color'  => 1
+                                                     ),
+                                    'SH703I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'SH703I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 240,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      ),
+                                    'N703IMYU' => array(
+                                                        'width'  => 240,
+                                                        'height' => 270,
+                                                        'depth'  => 262144,
+                                                        'color'  => 1
+                                                        ),
+                                    'SO703I' => array(
+                                                      'width'  => 240,
+                                                      'height' => 368,
+                                                      'depth'  => 262144,
+                                                      'color'  => 1
+                                                      )
+                                    );
+            }
+        }
+
+        return @$displayMap[ strtoupper($model) ];
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+
+/*
+ * Local Variables:
+ * mode: php
+ * coding: iso-8859-1
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * indent-tabs-mode: nil
+ * End:
+ */
+?>
Index: branches/comu/data/module/Net/UserAgent/Mobile/Display.php
===================================================================
--- branches/comu/data/module/Net/UserAgent/Mobile/Display.php	(revision 11984)
+++ branches/comu/data/module/Net/UserAgent/Mobile/Display.php	(revision 11984)
@@ -0,0 +1,268 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+/**
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id: Display.php,v 1.10 2007/02/20 15:00:06 kuboa Exp $
+ * @since      File available since Release 0.1
+ */
+
+// {{{ Net_UserAgent_Mobile_Display
+
+/**
+ * Display information for Net_UserAgent_Mobile
+ *
+ * Net_UserAgent_Mobile_Display is a class for display information on
+ * {@link Net_UserAgent_Mobile}. Handy for image resizing or dispatching.
+ *
+ * SYNOPSIS:
+ * <code>
+ * require_once 'Net/UserAgent/Mobile.php';
+ *
+ * $agent = &Net_UserAgent_Mobile::factory();
+ * $display = $agent->getDisplay();
+ *
+ * $width  = $display->getWidth();
+ * $height = $display->getHeight();
+ * list($width, $height) = $display->getSize();
+ *
+ * if ($display->isColor()) {
+ *     $depth = $display->getDepth();
+ * }
+ *
+ * // only available in DoCoMo 505i
+ * $width_bytes  = $display->getWidthBytes();
+ * $height_bytes = $display->getHeightBytes();
+ * </code>
+ *
+ * USING EXTERNAL MAP FILE:
+ * If the environment variable DOCOMO_MAP exists, the specified XML data will
+ * be used for DoCoMo display information.
+ *
+ * ex) Please add the following code.
+ * $_SERVER['DOCOMO_MAP'] = '/path/to/DoCoMoMap.xml';
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @since      Class available since Release 0.1
+ */
+class Net_UserAgent_Mobile_Display
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**
+     * width of the display
+     * @var integer
+     */
+    var $_width;
+
+    /**
+     * height of the display
+     * @var integer
+     */
+    var $_height;
+
+    /**
+     * depth of the display
+     * @var integer
+     */
+    var $_depth;
+
+    /**
+     * color capability of the display
+     * @var boolean
+     */
+    var $_color;
+
+    /**
+     * width (bytes) of the display
+     * @var integer
+     */
+    var $_widthBytes;
+
+    /**
+     * height (bytes) of the display
+     * @var integer
+     */
+    var $_heightBytes;
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     */
+
+    // }}}
+    // {{{ constructor
+
+    /**
+     * constructor
+     *
+     * @param array $data display infomation
+     */
+    function Net_UserAgent_Mobile_Display($data)
+    {
+        $this->_width  = (integer)@$data['width'];
+        $this->_height = (integer)@$data['height'];
+        $this->_depth  = (integer)@$data['depth'];
+        $this->_color  = (boolean)@$data['color'];
+
+        $this->_widthBytes  = (integer)@$data['width_bytes'];
+        $this->_heightBytes = (integer)@$data['height_bytes'];
+    }
+
+    // }}}
+    // {{{ calcSize()
+
+    /**
+     * returns width * height of the display
+     *
+     * @return integer
+     */
+    function calcSize()
+    {
+        return $this->_width * $this->_height;
+    }
+
+    // }}}
+    // {{{ getSize()
+
+    /**
+     * returns width with height of the display
+     *
+     * @return array
+     */
+    function getSize()
+    {
+        return array($this->_width, $this->_height);
+    }
+
+    // }}}
+    // {{{ getWidth()
+
+    /**
+     * returns width of the display
+     *
+     * @return integer
+     */
+    function getWidth()
+    {
+        return $this->_width;
+    }
+
+    // }}}
+    // {{{ getHeight()
+
+    /**
+     * returns height of the display
+     *
+     * @return integer
+     */
+    function getHeight()
+    {
+        return $this->_height;
+    }
+
+    // }}}
+    // {{{ getDepth()
+
+    /**
+     * returns depth of the display
+     *
+     * @return integer
+     */
+    function getDepth()
+    {
+        return $this->_depth;
+    }
+
+    // }}}
+    // {{{ isColor()
+
+    /**
+     * returns true if the display has color capability
+     *
+     * @return boolean
+     */
+    function isColor()
+    {
+        return $this->_color;
+    }
+
+    // }}}
+    // {{{ getWidthBytes()
+
+    /**
+     * returns width (bytes) of the display
+     *
+     * @return integer
+     */
+    function getWidthBytes()
+    {
+        return $this->_widthBytes;
+    }
+
+    // }}}
+    // {{{ getHeightBytes()
+
+    /**
+     * returns height (bytes) of the display
+     *
+     * @return integer
+     */
+    function getHeightBytes()
+    {
+        return $this->_heightBytes;
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+
+/*
+ * Local Variables:
+ * mode: php
+ * coding: iso-8859-1
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * indent-tabs-mode: nil
+ * End:
+ */
+?>
Index: branches/comu/data/module/Net/UserAgent/Mobile/Common.php
===================================================================
--- branches/comu/data/module/Net/UserAgent/Mobile/Common.php	(revision 11984)
+++ branches/comu/data/module/Net/UserAgent/Mobile/Common.php	(revision 11984)
@@ -0,0 +1,447 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+/**
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id: Common.php,v 1.15 2007/02/20 14:59:19 kuboa Exp $
+ * @since      File available since Release 0.1
+ */
+
+// {{{ Net_UserAgent_Mobile_Common
+
+/**
+ * Base class that is extended by each user agents implementor
+ *
+ * Net_UserAgent_Mobile_Common is a class for mobile user agent
+ * abstraction layer on Net_UserAgent_Mobile.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @since      Class available since Release 0.1
+ */
+class Net_UserAgent_Mobile_Common extends PEAR
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**
+     * User-Agent name like 'DoCoMo'
+     * @var string
+     */
+    var $name = '';
+
+    /**
+     * User-Agent version number like '1.0'
+     * @var string
+     */
+    var $version = '';
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**
+     * {@link Net_UserAgent_Mobile_Display} object
+     * @var object {@link Net_UserAgent_Mobile_Display}
+     */
+    var $_display;
+
+    /**
+     * Net_UserAgent_Mobile_Request_XXX object
+     * @var object {@link Net_UserAgent_Mobile_Request_Env}
+     */
+    var $_request;
+
+    /**
+     * {@link Net_UserAgent_Mobile_Error} object for error handling in the
+     *     constructor
+     * @var object
+     **/
+    var $_error = null;
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     */
+
+    // }}}
+    // {{{ constructor
+
+    /**
+     * constructor
+     *
+     * @param object $request a {@link Net_UserAgent_Mobile_Request_Env}
+     *     object
+     */
+    function Net_UserAgent_Mobile_Common($request)
+    {
+        parent::PEAR('Net_UserAgent_Mobile_Error');
+        $this->_request = $request;
+        if (Net_UserAgent_Mobile::isError($result = $this->parse())) {
+            $this->isError($result);
+        }
+    }
+
+    // }}}
+    // {{{ isError
+
+    /**
+     * Returns/set an error when the instance couldn't initialize properly
+     *
+     * @param object {@link Net_UserAgent_Mobile_Error} object when setting
+     *     an error
+     * @return object {@link Net_UserAgent_Mobile_Error} object
+     */
+    function &isError($error = null)
+    {
+        if ($error !== null) {
+            $this->_error = &$error;
+        }
+
+        return $this->_error;
+    }
+
+    // }}}
+    // {{{ raiseError()
+
+    /**
+     * This method is used to communicate an error and invoke error
+     * callbacks etc. Basically a wrapper for PEAR::raiseError without
+     * the message string.
+     *
+     * @param mixed $code integer error code, or a PEAR error object (all
+     *     other parameters are ignored if this parameter is an object
+     * @param int $mode error mode, see PEAR_Error docs
+     * @param mixed $options If error mode is PEAR_ERROR_TRIGGER, this is the
+     *     error level (E_USER_NOTICE etc). If error mode is
+     *     PEAR_ERROR_CALLBACK, this is the callback function, either as a
+     *     function name, or as an array of an object and method name. For
+     *     other error modes this parameter is ignored.
+     * @param string $userinfo Extra debug information. Defaults to the last
+     *     query and native error code.
+     * @return object a PEAR error object
+     * @see PEAR_Error
+     */
+    function &raiseError($code = NET_USERAGENT_MOBILE_ERROR, $mode = null,
+                         $options = null, $userinfo = null
+                         )
+    {
+
+        // The error is yet a Net_UserAgent_Mobile error object
+        if (is_object($code)) {
+            $error = &PEAR::raiseError($code, null, null, null, null, null,
+                                       true
+                                       );
+            return $error;
+        }
+
+        $error = &PEAR::raiseError(null, $code, $mode, $options, $userinfo,
+                                   'Net_UserAgent_Mobile_Error', true
+                                   );
+        return $error;
+    }
+
+    // }}}
+    // {{{ getUserAgent()
+
+    /**
+     * returns User-Agent string
+     *
+     * @return string
+     */
+    function getUserAgent()
+    {
+        return $this->getHeader('User-Agent');
+    }
+
+    // }}}
+    // {{{ getHeader()
+
+    /**
+     * returns a specified HTTP header
+     *
+     * @param string $header
+     * @return string
+     */
+    function getHeader($header)
+    {
+        return $this->_request->get($header);
+    }
+
+    // }}}
+    // {{{ getName()
+
+    /**
+     * returns User-Agent name like 'DoCoMo'
+     *
+     * @return string
+     */
+    function getName()
+    {
+        return $this->name;
+    }
+
+    // }}}
+    // {{{ getDisplay()
+
+    /**
+     * returns {@link Net_UserAgent_Mobile_Disply} object
+     *
+     * @return object a {@link Net_UserAgent_Mobile_Display} object, or a
+     *     PEAR error object on error
+     * @see Net_UserAgent_Mobile_Display
+     */
+    function getDisplay()
+    {
+        if (!is_object($this->_display)) {
+            $this->_display = $this->makeDisplay();
+        }
+        return $this->_display;
+    }
+
+    // }}}
+    // {{{ getVersion()
+
+    /**
+     * returns User-Agent version number like '1.0'
+     *
+     * @return string
+     */
+    function getVersion()
+    {
+        return $this->version;
+    }
+
+    // }}}
+    // {{{ noMatch()
+
+    /**
+     * generates a warning message for new variants
+     *
+     * @return object a PEAR error object
+     */
+    function noMatch()
+    {
+        return $this->raiseError(NET_USERAGENT_MOBILE_ERROR_NOMATCH, null,
+                                 null, $this->getUserAgent() .
+                                 ': might be new variants. Please contact the author of Net_UserAgent_Mobile!'
+                                 );
+    }
+
+    // }}}
+    // {{{ parse()
+
+    /**
+     * parse HTTP_USER_AGENT string (should be implemented in subclasses)
+     *
+     * @abstract
+     */
+    function parse()
+    {
+        die();
+    }
+
+    // }}}
+    // {{{ makeDisplay()
+
+    /**
+     * create a new Net_UserAgent_Mobile_Display class instance (should be
+     * implemented in subclasses)
+     *
+     * @abstract
+     */
+    function makeDisplay()
+    {
+        die();
+    }
+
+    // }}}
+    // {{{ isDoCoMo()
+
+    /**
+     * returns true if the agent is DoCoMo
+     *
+     * @return boolean
+     */
+    function isDoCoMo()
+    {
+        return false;
+    }
+
+    // }}}
+    // {{{ isJPhone()
+
+    /**
+     * returns true if the agent is J-PHONE
+     *
+     * @return boolean
+     */
+    function isJPhone()
+    {
+        return false;
+    }
+
+    // }}}
+    // {{{ isVodafone()
+
+    /**
+     * returns true if the agent is Vodafone
+     *
+     * @return boolean
+     */
+    function isVodafone()
+    {
+        return false;
+    }
+
+    // }}}
+    // {{{ isEZweb()
+
+    /**
+     * returns true if the agent is EZweb
+     *
+     * @return boolean
+     */
+    function isEZweb()
+    {
+        return false;
+    }
+
+    // }}}
+    // {{{ isAirHPhone()
+
+    /**
+     * returns true if the agent is AirH"PHONE
+     *
+     * @return boolean
+     */
+    function isAirHPhone()
+    {
+        return false;
+    }
+
+    // }}}
+    // {{{ isNonMobile()
+
+    /**
+     * returns true if the agent is NonMobile
+     *
+     * @return boolean
+     */
+    function isNonMobile()
+    {
+        return false;
+    }
+
+    // }}}
+    // {{{ isTUKa()
+
+    /**
+     * returns true if the agent is TU-Ka
+     *
+     * @return boolean
+     */
+    function isTUKa()
+    {
+        return false;
+    }
+
+    // }}}
+    // {{{ isWAP1()
+
+    /**
+     * returns true if the agent can speak WAP1 protocol
+     *
+     * @return boolean
+     */
+    function isWAP1()
+    {
+        return $this->isEZweb() && !$this->isWAP2();
+    }
+
+    // }}}
+    // {{{ isWAP2()
+
+    /**
+     * returns true if the agent can speak WAP2 protocol
+     *
+     * @return boolean
+     */
+    function isWAP2()
+    {
+        return $this->isEZweb() && $this->isXHTMLCompliant();
+    }
+
+    // }}}
+    // {{{ getCarrierShortName()
+
+    /**
+     * returns the short name of the carrier
+     *
+     * @abstract
+     */
+    function getCarrierShortName()
+    {
+        die();
+    }
+
+    // }}}
+    // {{{ getCarrierLongName()
+
+    /**
+     * returns the long name of the carrier
+     *
+     * @abstract
+     */
+    function getCarrierLongName()
+    {
+        die();
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+
+/*
+ * Local Variables:
+ * mode: php
+ * coding: iso-8859-1
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * indent-tabs-mode: nil
+ * End:
+ */
+?>
Index: branches/comu/data/module/Net/UserAgent/Mobile/Request.php
===================================================================
--- branches/comu/data/module/Net/UserAgent/Mobile/Request.php	(revision 11984)
+++ branches/comu/data/module/Net/UserAgent/Mobile/Request.php	(revision 11984)
@@ -0,0 +1,185 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+/**
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id: Request.php,v 1.6 2007/02/20 15:18:26 kuboa Exp $
+ * @since      File available since Release 0.1
+ */
+
+// {{{ Net_UserAgent_Mobile_Request
+
+/**
+ * Utility class that constructs appropriate class instance for miscellaneous
+ * HTTP header containers
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @since      Class available since Release 0.1
+ */
+class Net_UserAgent_Mobile_Request
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     * @static
+     */
+
+    // }}}
+    // {{{ factory()
+
+    /**
+     * create a new Net_UserAgent_Mobile_Request_XXX instance
+     *
+     * parses HTTP headers and constructs appropriate class instance.
+     * If no argument is supplied, $_SERVER is used.
+     *
+     * @param mixed $stuff User-Agent string or object that works with
+     *     HTTP_Request (not implemented)
+     * @return mixed a newly created Net_UserAgent_Request object
+     * @global array $_SERVER
+     */
+    function &factory($stuff = null)
+    {
+        if ($stuff === null) {
+            $request = &new Net_UserAgent_Mobile_Request_Env($_SERVER);
+        } else {
+            $request =
+                &new Net_UserAgent_Mobile_Request_Env(array(
+                                                            'HTTP_USER_AGENT' => $stuff)
+                                                      );
+        }
+        return $request;
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+// {{{ Net_UserAgent_Mobile_Request_Env
+
+/**
+ * provides easy way to access environment variables
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @since      Class available since Release 0.1
+ */
+class Net_UserAgent_Mobile_Request_Env
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**
+     * array of environment variables defined by Web Server
+     * @var array
+     */
+    var $_env;
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     */
+
+    // }}}
+    // {{{ constructor
+
+    /**
+     * constructor
+     *
+     * @param array $env
+     */
+    function Net_UserAgent_Mobile_Request_Env($env)
+    {
+        $this->_env = $env;
+    }
+
+    /**
+     * returns a specified HTTP Header
+     *
+     * @param string $header
+     * @return string
+     */
+    function get($header)
+    {
+        $header = strtr($header, '-', '_');
+        return @$this->_env[ 'HTTP_' . strtoupper($header) ];
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+
+/*
+ * Local Variables:
+ * mode: php
+ * coding: iso-8859-1
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * indent-tabs-mode: nil
+ * End:
+ */
+?>
Index: branches/comu/data/module/Net/UserAgent/Mobile/EZweb.php
===================================================================
--- branches/comu/data/module/Net/UserAgent/Mobile/EZweb.php	(revision 11984)
+++ branches/comu/data/module/Net/UserAgent/Mobile/EZweb.php	(revision 11984)
@@ -0,0 +1,347 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+/**
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id: EZweb.php,v 1.17 2007/02/20 15:19:07 kuboa Exp $
+ * @link       http://www.au.kddi.com/ezfactory/tec/spec/4_4.html
+ * @link       http://www.au.kddi.com/ezfactory/tec/spec/new_win/ezkishu.html
+ * @see        Net_UserAgent_Mobile_Common
+ * @since      File available since Release 0.1.0
+ */
+
+require_once(dirname(__FILE__) . '/Common.php');
+require_once(dirname(__FILE__) . '/Display.php');
+
+// {{{ Net_UserAgent_Mobile_EZweb
+
+/**
+ * EZweb implementation
+ *
+ * Net_UserAgent_Mobile_EZweb is a subclass of
+ * {@link Net_UserAgent_Mobile_Common}, which implements EZweb (WAP1.0/2.0)
+ * user agents.
+ *
+ * SYNOPSIS:
+ * <code>
+ * require_once 'Net/UserAgent/Mobile.php';
+ *
+ * $_SERVER['HTTP_USER_AGENT'] = 'UP.Browser/3.01-HI02 UP.Link/3.2.1.2';
+ * $agent = &Net_UserAgent_Mobile::factory();
+ *
+ * printf("Name: %s\n", $agent->getName()); // 'UP.Browser'
+ * printf("Version: %s\n", $agent->getVersion()); // 3.01
+ * printf("DeviceID: %s\n", $agent->getDeviceID()); // 'HI02'
+ * printf("Server: %s\n", $agent->getServer()); // 'UP.Link/3.2.1.2'
+ *
+ * e.g.) 'UP.Browser/3.01-HI02 UP.Link/3.2.1.2 (Google WAP Proxy/1.0)'
+ * printf("Comment: %s\n", $agent->getComment()); // 'Google WAP Proxy/1.0'
+ *
+ * e.g.) 'KDDI-TS21 UP.Browser/6.0.2.276 (GUI) MMP/1.1'
+ * if ($agent->isXHTMLCompliant()) {
+ *     print "XHTML compliant!\n"; // true
+ * }
+ * </code>
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @link       http://www.au.kddi.com/ezfactory/tec/spec/4_4.html
+ * @link       http://www.au.kddi.com/ezfactory/tec/spec/new_win/ezkishu.html
+ * @see        Net_UserAgent_Mobile_Common
+ * @since      Class available since Release 0.1.0
+ */
+class Net_UserAgent_Mobile_EZweb extends Net_UserAgent_Mobile_Common
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**
+     * name of the model like 'P502i'
+     * @var string
+     */
+    var $_model = '';
+
+    /**
+     * device ID like 'TS21'
+     * @var string
+     */
+    var $_deviceID = '';
+
+    /**
+     * server string like 'UP.Link/3.2.1.2'
+     * @var string
+     */
+    var $_serverName = '';
+
+    /**
+     * comment like 'Google WAP Proxy/1.0'
+     * @var string
+     */
+    var $_comment = null;
+
+    /**
+     * whether it's XHTML compliant or not
+     * @var boolean
+     */
+    var $_xhtmlCompliant = false;
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     */
+
+    // }}}
+    // {{{ isEZweb()
+
+    /**
+     * returns true
+     *
+     * @return boolean
+     */
+    function isEZweb()
+    {
+        return true;
+    }
+
+    // }}}
+    // {{{ isTUKa()
+
+    /**
+     * returns true if the agent is TU-Ka
+     *
+     * @return boolean
+     */
+    function isTUKa()
+    {
+        $tuka = substr($this->_deviceID, 2, 1);
+        if ($this->isWAP2()) {
+            if ($tuka == 'U') {
+                return true;
+            }
+        } else {
+            if ($tuka == 'T') {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+
+    // }}}
+    // {{{ parse()
+
+    /**
+     * parse HTTP_USER_AGENT string
+     */
+    function parse()
+    {
+        $agent = $this->getUserAgent();
+
+        if (preg_match('/^KDDI-(.*)/', $agent, $matches)) {
+
+            // KDDI-TS21 UP.Browser/6.0.2.276 (GUI) MMP/1.1
+            $this->_xhtmlCompliant = true;
+            list($this->_deviceID, $browser, $opt, $this->_serverName) =
+                explode(' ', $matches[1], 4);
+            list($this->name, $version) = explode('/', $browser);
+            $this->version = "$version $opt";
+        } else {
+
+            // UP.Browser/3.01-HI01 UP.Link/3.4.5.2
+            @list($browser, $this->_serverName, $comment) =
+                explode(' ', $agent, 3);
+            list($this->name, $software) = explode('/', $browser);
+            list($this->version, $this->_deviceID) =
+                explode('-', $software);
+            if ($comment) {
+                $this->_comment =
+                    preg_replace('/^\((.*)\)$/', '$1', $comment);
+            }
+        }
+
+        $this->_model = $this->_deviceID;
+    }
+
+    // }}}
+    // {{{ makeDisplay()
+
+    /**
+     * create a new {@link Net_UserAgent_Mobile_Display} class instance
+     *
+     * @return object a newly created {@link Net_UserAgent_Mobile_Display}
+     *     object
+     * @see Net_UserAgent_Mobile_Display
+     */
+    function makeDisplay()
+    {
+        @list($width, $height) =
+            explode(',', $this->getHeader('x-up-devcap-screenpixels'));
+        $screenDepth =
+            explode(',', $this->getHeader('x-up-devcap-screendepth'));
+        $depth = $screenDepth[0] ? pow(2, (integer)$screenDepth[0]) : 0;
+        $color =
+            $this->getHeader('x-up-devcap-iscolor') === '1' ? true : false;
+        return new Net_UserAgent_Mobile_Display(array(
+                                                      'width'  => $width,
+                                                      'height' => $height,
+                                                      'color'  => $color,
+                                                      'depth'  => $depth
+                                                      )
+                                                );
+    }
+
+    // }}}
+    // {{{ getModel()
+
+    /**
+     * returns name of the model (device ID) like 'TS21'
+     *
+     * @return string
+     */
+    function getModel()
+    {
+        return $this->_model;
+    }
+
+    // }}}
+    // {{{ getDeviceID()
+
+    /**
+     * returns device ID like 'TS21'
+     *
+     * @return string
+     */
+    function getDeviceID()
+    {
+        return $this->_deviceID;
+    }
+
+    // }}}
+    // {{{ getServer()
+
+    /**
+     * returns server string like 'UP.Link/3.2.1.2'
+     *
+     * @return string
+     */
+    function getServer()
+    {
+        return $this->_serverName;
+    }
+
+    // }}}
+    // {{{ getComment()
+
+    /**
+     * returns comment like 'Google WAP Proxy/1.0'. returns null if nothinng.
+     *
+     * @return boolean
+     */
+    function getComment()
+    {
+        return $this->_comment;
+    }
+
+    // }}}
+    // {{{ isXHTMLCompliant()
+
+    /**
+     * returns whether it's XHTML compliant or not
+     *
+     * @return boolean
+     */
+    function isXHTMLCompliant()
+    {
+        return $this->_xhtmlCompliant;
+    }
+
+    // }}}
+    // {{{ getCarrierShortName()
+
+    /**
+     * returns the short name of the carrier
+     *
+     * @return string
+     */
+    function getCarrierShortName()
+    {
+        return 'E';
+    }
+
+    // }}}
+    // {{{ getCarrierLongName()
+
+    /**
+     * returns the long name of the carrier
+     *
+     * @return string
+     */
+    function getCarrierLongName()
+    {
+        return 'EZweb';
+    }
+
+    // }}}
+    // {{{ isWIN()
+
+    /**
+     * Returns whether the agent is CDMA 1X WIN or not.
+     *
+     * @return boolean
+     */
+    function isWIN()
+    {
+        return substr($this->_deviceID, 2, 1) == 3 ? true : false;
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+
+/*
+ * Local Variables:
+ * mode: php
+ * coding: iso-8859-1
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * indent-tabs-mode: nil
+ * End:
+ */
+?>
Index: branches/comu/data/module/Net/UserAgent/Mobile/AirHPhone.php
===================================================================
--- branches/comu/data/module/Net/UserAgent/Mobile/AirHPhone.php	(revision 11984)
+++ branches/comu/data/module/Net/UserAgent/Mobile/AirHPhone.php	(revision 11984)
@@ -0,0 +1,285 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+/**
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id: AirHPhone.php,v 1.12 2007/02/20 14:39:45 kuboa Exp $
+ * @link       http://www.willcom-inc.com/ja/service/contents_service/club_air_edge/for_phone/homepage/index.html
+ * @see        Net_UserAgent_Mobile_Common
+ * @since      File available since Release 0.5
+ */
+
+require_once(dirname(__FILE__) . '/Common.php');
+require_once(dirname(__FILE__) . '/Display.php');
+
+// {{{ Net_UserAgent_Mobile_AirHPhone
+
+/**
+ * AirH"PHONE implementation
+ *
+ * Net_UserAgent_Mobile_AirHPhone is a subclass of
+ * {@link Net_UserAgent_Mobile_Common}, which implements DDI POCKET's
+ * AirH"PHONE user agents.
+ *
+ * SYNOPSIS:
+ * <code>
+ * require_once 'Net/UserAgent/Mobile.php';
+ *
+ * $_SERVER['HTTP_USER_AGENT'] =
+ *     'Mozilla/3.0(DDIPOCKET;JRC/AH-J3001V,AH-J3002V/1.0/0100/c50)CNF/2.0';
+ * $agent = &Net_UserAgent_Mobile::factory();
+ *
+ * printf("Name: %s\n", $agent->getName()); // 'DDIPOCKET'
+ * printf("Verdor: %s\n", $agent->getVendor()); // 'JRC'
+ * printf("Model: %s\n", $agent->getModel()); // 'AH-J3001V,AH-J3002V'
+ * printf("Model Version: %s\n", $agent->getModelVersion()); // '1.0'
+ * printf("Browser Version: %s\n", $agent->getBrowserVersion()); // '0100'
+ * printf("Cache Size: %s\n", $agent->getCacheSize()); // 50
+ * </code>
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @link       http://www.willcom-inc.com/ja/service/contents_service/club_air_edge/for_phone/homepage/index.html
+ * @see        Net_UserAgent_Mobile_Common
+ * @since      Class available since Release 0.5
+ */
+class Net_UserAgent_Mobile_AirHPhone extends Net_UserAgent_Mobile_Common
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**
+     * User-Agent name
+     * @var string
+     */
+    var $name = 'WILLCOM';
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**
+     * vendor name
+     * @var string
+     */
+    var $_vendor;
+
+    /**
+     * model name
+     * @var string
+     */
+    var $_model;
+
+    /**
+     * version number of the model
+     * @var string
+     */
+    var $_modelVersion;
+
+    /**
+     * version number of the browser
+     * @var string
+     */
+    var $_browserVersion;
+
+    /**
+     * cache size as killobytes unit
+     * @var integer
+     */
+    var $_cacheSize;
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     */
+
+    // }}}
+    // {{{ isAirHPhone()
+
+    /**
+     * returns true
+     *
+     * @return boolean
+     */
+    function isAirHPhone()
+    {
+        return true;
+    }
+
+    // }}}
+    // {{{ parse()
+
+    /**
+     * parse HTTP_USER_AGENT string
+     */
+    function parse()
+    {
+        $agent = $this->getUserAgent();
+        if (preg_match('!^Mozilla/3\.0\((?:DDIPOCKET|WILLCOM);(.*)\)!',
+                       $agent, $matches)
+            ) {
+            list($this->_vendor, $this->_model, $this->_modelVersion,
+                 $this->_browserVersion, $cache) =
+                explode('/', $matches[1]);
+            if (!preg_match('/^[Cc](\d+)/', $cache, $matches)) {
+                return $this->noMatch();
+            }
+            $this->_cacheSize = (integer)$matches[1];
+        } else {
+            $this->noMatch();
+        }
+    }
+
+    // }}}
+    // {{{ makeDisplay()
+
+    /**
+     * create a new {@link Net_UserAgent_Mobile_Display} class instance
+     *
+     * @return object a newly created {@link Net_UserAgent_Mobile_Display}
+     *     object
+     * @see Net_UserAgent_Mobile_Display
+     */
+    function makeDisplay()
+    {
+        return new Net_UserAgent_Mobile_Display(null);
+    }
+
+    // }}}
+    // {{{ getVendor()
+
+    /**
+     * returns vendor name
+     *
+     * @return string
+     */
+    function getVendor()
+    {
+        return $this->_vendor;
+    }
+
+    // }}}
+    // {{{ getModel()
+
+    /**
+     * returns model name. Note that model names are separated with ','.
+     *
+     * @return string
+     */
+    function getModel()
+    {
+        return $this->_model;
+    }
+
+    // }}}
+    // {{{ getModelVersion()
+
+    /**
+     * returns version number of the model
+     *
+     * @return string
+     */
+    function getModelVersion()
+    {
+        return $this->_modelVersion;
+    }
+
+    // }}}
+    // {{{ getBrowserVersion()
+
+    /**
+     * returns version number of the browser
+     *
+     * @return string
+     */
+    function getBrowserVersion()
+    {
+        return $this->_browserVersion;
+    }
+
+    // }}}
+    // {{{ getCacheSize()
+
+    /**
+     * returns cache size as killobytes unit
+     *
+     * @return integer
+     */
+    function getCacheSize()
+    {
+        return $this->_cacheSize;
+    }
+
+    // }}}
+    // {{{ getCarrierShortName()
+
+    /**
+     * returns the short name of the carrier
+     *
+     * @return string
+     */
+    function getCarrierShortName()
+    {
+        return 'H';
+    }
+
+    // }}}
+    // {{{ getCarrierLongName()
+
+    /**
+     * returns the long name of the carrier
+     *
+     * @return string
+     */
+    function getCarrierLongName()
+    {
+        return 'AirH';
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+
+/*
+ * Local Variables:
+ * mode: php
+ * coding: iso-8859-1
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * indent-tabs-mode: nil
+ * End:
+ */
+?>
Index: branches/comu/data/module/Net/UserAgent/Mobile/DoCoMo.php
===================================================================
--- branches/comu/data/module/Net/UserAgent/Mobile/DoCoMo.php	(revision 11984)
+++ branches/comu/data/module/Net/UserAgent/Mobile/DoCoMo.php	(revision 11984)
@@ -0,0 +1,587 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+/**
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id: DoCoMo.php,v 1.35 2007/02/20 18:41:04 kuboa Exp $
+ * @link       http://www.nttdocomo.co.jp/service/imode/make/content/spec/useragent/index.html
+ * @see        Net_UserAgent_Mobile_Common
+ * @since      File available since Release 0.1
+ */
+
+require_once dirname(__FILE__) . '/Common.php';
+require_once dirname(__FILE__) . '/Display.php';
+require_once dirname(__FILE__) . '/DoCoMoDisplayMap.php';
+
+// {{{ Net_UserAgent_Mobile_DoCoMo
+
+/**
+ * NTT DoCoMo implementation
+ *
+ * Net_UserAgent_Mobile_DoCoMo is a subclass of
+ * {@link Net_UserAgent_Mobile_Common}, which implements NTT docomo i-mode
+ * user agents.
+ *
+ * SYNOPSIS:
+ * <code>
+ * require_once 'Net/UserAgent/Mobile.php';
+ *
+ * $_SERVER['HTTP_USER_AGENT'] = 'DoCoMo/1.0/P502i/c10';
+ * $agent = &Net_UserAgent_Mobile::factory();
+ *
+ * printf("Name: %s\n", $agent->getName()); // 'DoCoMo'
+ * printf("Version: %s\n", $agent->getVersion()); // 1.0
+ * printf("HTML version: %s\n", $agent->getHTMLVersion()); // 2.0
+ * printf("Model: %s\n", $agent->getModel()); // 'P502i'
+ * printf("Cache: %dk\n", $agent->getCacheSize()); // 10
+ * if ($agent->isFOMA()) {
+ *     print "FOMA\n";             // false
+ * }
+ * printf("Vendor: %s\n", $agent->getVendor()); // 'P'
+ * printf("Series: %s\n", $agent->getSeries()); // '502i'
+ *
+ * // only available with <form utn>
+ * // e.g.) 'DoCoMo/1.0/P503i/c10/serNMABH200331';
+ * printf("Serial: %s\n", $agent->getSerialNumber()); // 'NMABH200331'
+ *
+ * // e.g.) 'DoCoMo/2.0 N2001(c10;ser0123456789abcde;icc01234567890123456789)';
+ * printf("Serial: %s\n", $agent->getSerialNumber()); // '0123456789abcde'
+ * printf("Card ID: %s\n", $agent->getCardID()); // '01234567890123456789'
+ *
+ * // e.g.) 'DoCoMo/1.0/P502i (Google CHTML Proxy/1.0)'
+ * printf("Comment: %s\n", $agent->getComment()); // 'Google CHTML Proxy/1.0'
+ *
+ * // e.g.) 'DoCoMo/1.0/D505i/c20/TB/W20H10'
+ * printf("Status: %s\n", $agent->getStatus()); // 'TB'
+ *
+ * // only available in eggy/M-stage
+ * // e.g.) 'DoCoMo/1.0/eggy/c300/s32/kPHS-K'
+ * printf("Bandwidth: %dkbps\n", $agent->getBandwidth()); // 32
+ * </code>
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @link       http://www.nttdocomo.co.jp/service/imode/make/content/spec/useragent/index.html
+ * @see        Net_UserAgent_Mobile_Common
+ * @since      Class available since Release 0.1
+ */
+class Net_UserAgent_Mobile_DoCoMo extends Net_UserAgent_Mobile_Common
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**
+     * name of the model like 'P502i'
+     * @var string
+     */
+    var $_model = '';
+
+    /**
+     * status of the cache (TC, TB, TD, TJ)
+     * @var string
+     */
+    var $_status = '';
+
+    /**
+     * bandwidth like 32 as kilobytes unit
+     * @var integer
+     */
+    var $_bandwidth = null;
+
+    /**
+     * hardware unique serial number
+     * @var string
+     */
+    var $_serialNumber = null;
+
+    /**
+     * whether it's FOMA or not
+     * @var boolean
+     */
+    var $_isFOMA = false;
+
+    /**
+     * FOMA Card ID (20 digit alphanumeric)
+     * @var string
+     */
+    var $_cardID = null;
+
+    /**
+     * comment on user agent string like 'Google Proxy'
+     * @var string
+     */
+    var $_comment = null;
+
+    /**
+     * cache size as killobytes unit
+     * @var integer
+     */
+    var $_cacheSize;
+
+    /**
+     * width and height of the display
+     * @var string
+     */
+    var $_displayBytes = '';
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     */
+
+    // }}}
+    // {{{ isDoCoMo()
+
+    /**
+     * returns true
+     *
+     * @return boolean
+     */
+    function isDoCoMo()
+    {
+        return true;
+    }
+
+    // }}}
+    // {{{ parse()
+
+    /**
+     * parse HTTP_USER_AGENT string
+     *
+     * @return mixed void, or a PEAR error object on error
+     */
+    function parse()
+    {
+        @list($main, $foma_or_comment) =
+            explode(' ', $this->getUserAgent(), 2);
+
+        if ($foma_or_comment
+            && preg_match('/^\((.*)\)$/', $foma_or_comment, $matches)
+            ) {
+
+            // DoCoMo/1.0/P209is (Google CHTML Proxy/1.0)
+            $this->_comment = $matches[1];
+            $result = $this->_parseMain($main);
+        } elseif ($foma_or_comment) {
+
+            // DoCoMo/2.0 N2001(c10;ser0123456789abcde;icc01234567890123456789)
+            $this->_isFOMA = true;
+            list($this->name, $this->version) = explode('/', $main);
+            $result = $this->_parseFOMA($foma_or_comment);
+        } else {
+
+            // DoCoMo/1.0/R692i/c10
+            $result = $this->_parseMain($main);
+        }
+
+        if (Net_UserAgent_Mobile::isError($result)) {
+            return $result;
+        }
+    }
+
+    // }}}
+    // {{{ makeDisplay()
+
+    /**
+     * create a new {@link Net_UserAgent_Mobile_Display} class instance
+     *
+     * @return object a newly created {@link Net_UserAgent_Mobile_Display}
+     *     object
+     * @see Net_UserAgent_Mobile_Display
+     * @see Net_UserAgent_Mobile_DoCoMoDisplayMap::get()
+     */
+    function makeDisplay()
+    {
+        $display = Net_UserAgent_Mobile_DoCoMoDisplayMap::get($this->_model);
+        if ($this->_displayBytes !== '') {
+            list($widthBytes, $heightBytes) =
+                explode('*', $this->_displayBytes);
+            $display['width_bytes']  = $widthBytes;
+            $display['height_bytes'] = $heightBytes;
+        }
+        return new Net_UserAgent_Mobile_Display($display);
+    }
+
+    // }}}
+    // {{{ getHTMLVersion()
+
+    /**
+     * returns supported HTML version like '3.0'. retuns null if unknown.
+     *
+     * @return string
+     */
+    function getHTMLVersion()
+    {
+        static $htmlVersionMap;
+        if (!isset($htmlVersionMap)) {
+            $htmlVersionMap = array(
+                                    '[DFNP]501i' => '1.0',
+                                    '502i|821i|209i|651|691i|(F|N|P|KO)210i|^F671i$' => '2.0',
+                                    '(D210i|SO210i)|503i|211i|SH251i|692i|200[12]|2101V' => '3.0',
+                                    '504i|251i|^F671iS$|212i|2051|2102V|661i|2701|672i|SO213i|850i' => '4.0',
+                                    'eggy|P751v' => '3.2',
+                                    '505i|252i|900i|506i|880i|253i|P213i|901i|700i|851i|701i|881i|^SA800i$|600i|^L601i$|^M702i(S|G)$' => '5.0',
+                                    '902i|702i|851i|882i|^N601i$|^D800iDS$|^P703imyu$' => '6.0',
+                                    '903i|703i' => '7.0'
+                                    );
+        }
+
+        foreach ($htmlVersionMap as $key => $value) {
+            if (preg_match("/$key/", $this->_model)) {
+                return $value;
+            }
+        }
+        return null;
+    }
+
+    // }}}
+    // {{{ getCacheSize()
+
+    /**
+     * returns cache size as kilobytes unit. returns 5 if unknown.
+     *
+     * @return integer
+     */
+    function getCacheSize()
+    {
+        if ($this->_cacheSize) {
+            return $this->_cacheSize;
+        }
+
+        static $defaultCacheSize;
+        if (!isset($defaultCacheSize)) {
+            $defaultCacheSize = 5;
+        }
+        return $defaultCacheSize;
+    }
+
+    // }}}
+    // {{{ getSeries()
+
+    /**
+     * returns series name like '502i'. returns null if unknown.
+     *
+     * @return string
+     */
+    function getSeries()
+    {
+        if ($this->isFOMA() && preg_match('/(\d{4})/', $this->_model)) {
+            return 'FOMA';
+        }
+
+        if (preg_match('/(\d{3}i)/', $this->_model, $matches)) {
+            return $matches[1];
+        }
+
+        if ($this->_model == 'P651ps') {
+            return '651';
+        }
+
+        return null;
+    }
+
+    // }}}
+    // {{{ getVendor()
+
+    /**
+     * returns vender code like 'SO' for Sony. returns null if unknown.
+     *
+     * @return string
+     */
+    function getVendor()
+    {
+        if (preg_match('/([A-Z]+)\d/', $this->_model, $matches)) {
+            return $matches[1];
+        }
+        return null;
+    }
+
+    // }}}
+    // {{{ getModel()
+
+    /**
+     * returns name of the model like 'P502i'
+     *
+     * @return string
+     */
+    function getModel()
+    {
+        return $this->_model;
+    }
+
+    // }}}
+    // {{{ getStatus()
+
+    /**
+     * returns status like "TB", "TC", "TD" or "TJ", which means:
+     * 
+     * TB | Browsers
+     * TC | Browsers with image off (only Available in HTML 5.0)
+     * TD | Fetching JAR
+     * TJ | i-Appli
+     *
+     * @return string
+     */
+    function getStatus()
+    {
+        return $this->_status;
+    }
+
+    // }}}
+    // {{{ getBandwidth()
+
+    /**
+     * returns bandwidth like 32 as killobytes unit. Only vailable in eggy,
+     * returns null otherwise.
+     *
+     * @return integer
+     */
+    function getBandwidth()
+    {
+        return $this->_bandwidth;
+    }
+
+    // }}}
+    // {{{ getSerialNumber()
+
+    /**
+     * returns hardware unique serial number (15 digit in FOMA, 11 digit
+     * otherwise alphanumeric). Only available with form utn attribute.
+     * returns null otherwise.
+     *
+     * @return string
+     */
+    function getSerialNumber()
+    {
+        return $this->_serialNumber;
+    }
+
+    // }}}
+    // {{{ isFOMA()
+
+    /**
+     * retuns whether it's FOMA or not
+     *
+     * @return boolean
+     */
+    function isFOMA()
+    {
+        return $this->_isFOMA;
+    }
+
+    // }}}
+    // {{{ getComment()
+
+    /**
+     * returns comment on user agent string like 'Google Proxy'. returns null
+     * otherwise.
+     *
+     * @return string
+     */
+    function getComment()
+    {
+        return $this->_comment;
+    }
+
+    // }}}
+    // {{{ getCardID()
+
+    /**
+     * returns FOMA Card ID (20 digit alphanumeric). Only available in FOMA
+     * with <form utn> attribute. returns null otherwise.
+     *
+     * @return string
+     */ 
+    function getCardID()
+    {
+        return $this->_cardID;
+    }
+
+    // }}}
+    // {{{ isGPS()
+
+    /**
+     * @return boolean
+     */ 
+    function isGPS()
+    {
+        static $gpsModels;
+        if (!isset($gpsModels)) {
+            $gpsModels = array('F661i', 'F505iGPS');
+        }
+        return in_array($this->_model, $gpsModels);
+    }
+
+    // }}}
+    // {{{ getCarrierShortName()
+
+    /**
+     * returns the short name of the carrier
+     *
+     * @return string
+     */
+    function getCarrierShortName()
+    {
+        return 'I';
+    }
+
+    // }}}
+    // {{{ getCarrierLongName()
+
+    /**
+     * returns the long name of the carrier
+     *
+     * @return string
+     */
+    function getCarrierLongName()
+    {
+        return 'DoCoMo';
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    // }}}
+    // {{{ _parseMain()
+
+    /**
+     * parse main part of HTTP_USER_AGENT string (not FOMA)
+     *
+     * @param string $main main part of HTTP_USER_AGENT string
+     * @return mixed void, or a PEAR error object on error
+     */ 
+    function _parseMain($main)
+    {
+        @list($this->name, $this->version, $this->_model, $cache, $rest) =
+            explode('/', $main, 5);
+        if ($this->_model === 'SH505i2') {
+            $this->_model = 'SH505i';
+        }
+
+        if ($cache) {
+            if (!preg_match('/^c(\d+)/', $cache, $matches)) {
+                return $this->noMatch();
+            }
+            $this->_cacheSize = (integer)$matches[1];
+        }
+
+        if ($rest) {
+            $rest = explode('/', $rest);
+            foreach ($rest as $value) {
+                if (preg_match('/^ser(\w{11})$/', $value, $matches)) {
+                    $this->_serialNumber = $matches[1];
+                    continue;
+                }
+                if (preg_match('/^(T[CDBJ])$/', $value, $matches)) {
+                    $this->_status = $matches[1];
+                    continue;
+                }
+                if (preg_match('/^s(\d+)$/', $value, $matches)) {
+                    $this->_bandwidth = (integer)$matches[1];
+                    continue;
+                }
+                if (preg_match('/^W(\d+)H(\d+)$/', $value, $matches)) {
+                    $this->_displayBytes = "{$matches[1]}*{$matches[2]}";
+                    continue;
+                }
+            }
+        }
+    }
+
+    // }}}
+    // {{{ _parseFOMA()
+
+    /**
+     * parse main part of HTTP_USER_AGENT string (FOMA)
+     *
+     * @param string $foma main part of HTTP_USER_AGENT string
+     * @return mixed void, or a PEAR error object on error
+     */ 
+    function _parseFOMA($foma)
+    {
+        if (!preg_match('/^([^(]+)/', $foma, $matches)) {
+            return $this->noMatch();
+        }
+        $this->_model = $matches[1];
+        if ($matches[1] === 'MST_v_SH2101V') {
+            $this->_model = 'SH2101V';
+        }
+
+        if (preg_match('/^[^(]+\((.*?)\)$/', $foma, $matches)) {
+            $rest = explode(';', $matches[1]);
+            foreach ($rest as $value) {
+                if (preg_match('/^c(\d+)/', $value, $matches)) {
+                    $this->_cacheSize = (integer)$matches[1];
+                    continue;
+                }
+                if (preg_match('/^ser(\w{15})$/', $value, $matches)) {
+                    $this->_serialNumber = $matches[1];
+                    continue;
+                }
+                if (preg_match('/^(T[CDBJ])$/', $value, $matches)) {
+                    $this->_status = $matches[1];
+                    continue;
+                }
+                if (preg_match('/^icc(\w{20})?$/', $value, $matches)) {
+                    if (count($matches) == 2) {
+                        $this->_cardID = $matches[1];
+                    }
+                    continue;
+                }
+                if (preg_match('/^W(\d+)H(\d+)$/', $value, $matches)) {
+                    $this->_displayBytes = "{$matches[1]}*{$matches[2]}";
+                    continue;
+                }
+                return $this->noMatch();
+            }
+        }
+    }
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+
+/*
+ * Local Variables:
+ * mode: php
+ * coding: iso-8859-1
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * indent-tabs-mode: nil
+ * End:
+ */
+?>
Index: branches/comu/data/module/Net/UserAgent/Mobile/Vodafone.php
===================================================================
--- branches/comu/data/module/Net/UserAgent/Mobile/Vodafone.php	(revision 11984)
+++ branches/comu/data/module/Net/UserAgent/Mobile/Vodafone.php	(revision 11984)
@@ -0,0 +1,557 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+/**
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id: Vodafone.php,v 1.12 2007/02/20 15:21:05 kuboa Exp $
+ * @since      File available since Release 0.20.0
+ */
+
+require_once dirname(__FILE__) . '/Common.php';
+require_once dirname(__FILE__) . '/Display.php';
+
+// {{{ Net_UserAgent_Mobile_Vodafone
+
+/**
+ * Vodafone implementation
+ *
+ * Net_UserAgent_Mobile_Vodafone is a subclass of
+ * {@link Net_UserAgent_Mobile_Common}, which implements Vodafone user agents.
+ *
+ * SYNOPSIS:
+ * <code>
+ * require_once 'Net/UserAgent/Mobile.php';
+ *
+ * $_SERVER['HTTP_USER_AGENT'] = 'J-PHONE/2.0/J-DN02';
+ * $agent = &Net_UserAgent_Mobile::factory();
+ *
+ * printf("Name: %s\n", $agent->getName()); // 'J-PHONE'
+ * printf("Version: %s\n", $agent->getVersion()); // 2.0
+ * printf("Model: %s\n", $agent->getModel()); // 'J-DN02'
+ * if ($agent->isPacketCompliant()) {
+ *     print "Packet is compliant.\n"; // false
+ * }
+ *
+ * // only availabe in Java compliant
+ * // e.g.) 'J-PHONE/4.0/J-SH51/SNXXXXXXXXX SH/0001a Profile/MIDP-1.0 Configuration/CLDC-1.0 Ext-Profile/JSCL-1.1.0'
+ * printf("Serial: %s\n", $agent->getSerialNumber()); // XXXXXXXXX
+ * printf("Vendor: %s\n", $agent->getVendor()); // 'SH'
+ * printf("Vendor Version: %s\n", $agent->getVendorVersion()); // '0001a'
+ *
+ * $info = $agent->getJavaInfo();  // array
+ * foreach ($info as $key => $value) {
+ *     print "$key: $value\n";
+ * }
+ * </code>
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @link       http://developers.vodafone.jp/dp/tool_dl/web/useragent.php
+ * @link       http://developers.vodafone.jp/dp/tool_dl/web/position.php
+ * @see        Net_UserAgent_Mobile_Common
+ * @since      Class available since Release 0.20.0
+ */
+class Net_UserAgent_Mobile_Vodafone extends Net_UserAgent_Mobile_Common
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**
+     * name of the model like 'J-DN02'
+     * @var string
+     */
+    var $_model = '';
+
+    /**
+     * whether the agent is packet connection complicant or not
+     * @var boolean
+     */
+    var $_packetCompliant = false;
+
+    /**
+     * terminal unique serial number
+     * @var string
+     */
+    var $_serialNumber = null;
+
+    /**
+     * vendor code like 'SH'
+     * @var string
+     */
+    var $_vendor = '';
+
+    /**
+     * vendor version like '0001a'
+     * @var string
+     */
+    var $_vendorVersion = null;
+
+    /**
+     * Java profiles
+     * @var array
+     */
+    var $_javaInfo = array();
+
+    /**
+     * whether the agent is 3G
+     * @var boolean
+     */
+    var $_is3G = true;
+
+    /**
+     * the name of the mobile phone
+     * @var string
+     */
+    var $_msname = '';
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     */
+
+    // }}}
+    // {{{ isJPhone()
+
+    /**
+     * returns true
+     *
+     * @return boolean
+     */
+    function isJPhone()
+    {
+        return true;
+    }
+
+    // }}}
+    // {{{ isVodafone()
+
+    /**
+     * returns true
+     *
+     * @return boolean
+     */
+    function isVodafone()
+    {
+        return true;
+    }
+
+    // }}}
+    // {{{ parse()
+
+    /**
+     * parse HTTP_USER_AGENT string
+     *
+     * @return mixed void, or a PEAR error object on error
+     */
+    function parse()
+    {
+        $agent = explode(' ', $this->getUserAgent());
+        preg_match('!^(?:(SoftBank|Vodafone|J-PHONE)/\d\.\d|MOT-)!',
+                   $agent[0], $matches
+                   );
+        if (count($matches) > 1) {
+            $carrier = $matches[1];
+        } else {
+            $carrier = 'Motorola';
+        }
+
+        switch ($carrier) {
+        case 'Vodafone':
+        case 'SoftBank':
+            $result = $this->_parseVodafone($agent);
+            break;
+        case 'J-PHONE':
+            $result = $this->_parseJphone($agent);
+            break;
+        case 'Motorola':
+            $result = $this->_parseMotorola($agent);
+            break;
+        }
+
+        if (Net_UserAgent_Mobile::isError($result)) {
+            return $result;
+        }
+
+        $this->_msname = $this->getHeader('x-jphone-msname');
+    }
+
+    // }}}
+    // {{{ makeDisplay()
+
+    /**
+     * create a new {@link Net_UserAgent_Mobile_Display} class instance
+     *
+     * @return object a newly created {@link Net_UserAgent_Mobile_Display}
+     *     object
+     * @see Net_UserAgent_Mobile_Display
+     */
+    function makeDisplay() 
+    {
+        @list($width, $height) =
+            explode('*', $this->getHeader('x-jphone-display'));
+        $color = false;
+        $depth = 0;
+        if ($color_string = $this->getHeader('x-jphone-color')) {
+            preg_match('!^([CG])(\d+)$!', $color_string, $matches);
+            $color = $matches[1] === 'C' ? true : false;
+            $depth = $matches[2];
+        }
+        return new Net_UserAgent_Mobile_Display(array(
+                                                      'width'  => $width,
+                                                      'height' => $height,
+                                                      'depth'  => $depth,
+                                                      'color'  => $color)
+                                                );
+    }
+
+    // }}}
+    // {{{ getModel()
+
+    /**
+     * returns name of the model like 'J-DN02'
+     *
+     * @return string
+     */
+    function getModel()
+    {
+        return $this->_model;
+    }
+
+    // }}}
+    // {{{ isPacketCompliant()
+
+    /**
+     * returns whether the agent is packet connection complicant or not
+     *
+     * @return boolean
+     */
+    function isPacketCompliant()
+    {
+        return $this->_packetCompliant;
+    }
+
+    // }}}
+    // {{{ getSerialNumber()
+
+    /**
+     * return terminal unique serial number. returns null if user forbids to
+     * send his/her serial number.
+     *
+     * @return string
+     */
+    function getSerialNumber()
+    {
+        return $this->_serialNumber;
+    }
+
+    // }}}
+    // {{{ getVendor()
+
+    /**
+     * returns vendor code like 'SH'
+     *
+     * @return string
+     */
+    function getVendor()
+    {
+        return $this->_vendor;
+    }
+
+    // }}}
+    // {{{ getVendorVersion()
+
+    /**
+     * returns vendor version like '0001a'. returns null if unknown.
+     *
+     * @return string
+     */
+    function getVendorVersion()
+    {
+        return $this->_vendorVersion;
+    }
+
+    // }}}
+    // {{{ getJavaInfo()
+
+    /**
+     * returns array of Java profiles
+     *
+     * Array structure is something like:
+     *
+     * - 'Profile'       => 'MIDP-1.0',
+     * - 'Configuration' => 'CLDC-1.0',
+     * - 'Ext-Profile'   => 'JSCL-1.1.0'
+     *
+     * @return array
+     */
+    function getJavaInfo()
+    {
+        return $this->_javaInfo;
+    }
+
+    // }}}
+    // {{{ getCarrierShortName()
+
+    /**
+     * returns the short name of the carrier
+     *
+     * @return string
+     */
+    function getCarrierShortName()
+    {
+        return 'V';
+    }
+
+    // }}}
+    // {{{ getCarrierLongName()
+
+    /**
+     * returns the long name of the carrier
+     *
+     * @return string
+     */
+    function getCarrierLongName()
+    {
+        return 'Vodafone';
+    }
+
+    // }}}
+    // {{{ isTypeC()
+
+    /**
+     * returns true if the type is C
+     *
+     * @return boolean
+     */
+    function isTypeC()
+    {
+        if ($this->_is3G || !preg_match('!^[32]\.!', $this->version)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    // }}}
+    // {{{ isTypeP()
+
+    /**
+     * returns true if the type is P
+     *
+     * @return boolean
+     */
+    function isTypeP()
+    {
+        if ($this->_is3G || !preg_match('!^4\.!', $this->version)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    // }}}
+    // {{{ isTypeW()
+
+    /**
+     * returns true if the type is W
+     *
+     * @return boolean
+     */
+    function isTypeW()
+    {
+        if ($this->_is3G || !preg_match('!^5\.!', $this->version)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    // }}}
+    // {{{ isType3GC()
+
+    /**
+     * returns true if the type is 3GC
+     *
+     * @return boolean
+     */
+    function isType3GC()
+    {
+        return $this->_is3G;
+    }
+
+    // }}}
+    // {{{ getMsname()
+
+    /**
+     * returns the name of the mobile phone
+     *
+     * @return string the name of the mobile phone
+     */
+    function getMsname()
+    {
+        return $this->_msname;
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    // }}}
+    // {{{ _parseVodafone()
+
+    /**
+     * parse HTTP_USER_AGENT string for the Vodafone 3G aegnt
+     *
+     * @param array $agent parts of the User-Agent string
+     * @return mixed void, or a PEAR error object on error
+     */
+    function _parseVodafone(&$agent)
+    {
+        $count = count($agent);
+        $this->_packetCompliant = true;
+
+        // Vodafone/1.0/V702NK/NKJ001 Series60/2.6 Nokia6630/2.39.148 Profile/MIDP-2.0 Configuration/CLDC-1.1
+        // Vodafone/1.0/V702NK/NKJ001/SN123456789012345 Series60/2.6 Nokia6630/2.39.148 Profile/MIDP-2.0 Configuration/CLDC-1.1
+        // Vodafone/1.0/V802SE/SEJ001/SN123456789012345 Browser/SEMC-Browser/4.1 Profile/MIDP-2.0 Configuration/CLDC-1.1
+        @list($this->name, $this->version, $this->_model, $modelVersion,
+              $serialNumber) = explode('/', $agent[0]);
+        if ($serialNumber) {
+            if (!preg_match('!^SN(.+)!', $serialNumber, $matches)) {
+                return $this->noMatch();
+            }
+            $this->_serialNumber = $matches[1];
+        }
+
+        if (!preg_match('!^([a-z]+)((?:[a-z]|\d){4})$!i', $modelVersion, $matches)) {
+            return $this->noMatch();
+        }
+
+        $this->_vendor = $matches[1];
+        $this->_vendorVersion = $matches[2];
+
+        for ($i = 2; $i < $count; ++$i) {
+            list($key, $value) = explode('/', $agent[$i]);
+            $this->_javaInfo[$key] = $value;
+        }
+    }
+
+    // }}}
+    // {{{ _parseJphone()
+
+    /**
+     * parse HTTP_USER_AGENT string for the ancient agent
+     *
+     * @param array $agent parts of the User-Agent string
+     * @return mixed void, or a PEAR error object on error
+     */
+    function _parseJphone(&$agent)
+    {
+        $count = count($agent);
+        $this->_is3G = false;
+
+        if ($count > 1) {
+
+            // J-PHONE/4.0/J-SH51/SNJSHA3029293 SH/0001aa Profile/MIDP-1.0 Configuration/CLDC-1.0 Ext-Profile/JSCL-1.1.0
+            $this->_packetCompliant = true;
+            @list($this->name, $this->version, $this->_model,
+                  $serialNumber) = explode('/', $agent[0]);
+            if ($serialNumber) {
+                if (!preg_match('!^SN(.+)!', $serialNumber, $matches)) {
+                    return $this->noMatch();
+                }
+                $this->_serialNumber = $matches[1];
+            }
+            list($this->_vendor, $this->_vendorVersion) =
+                explode('/', $agent[1]);
+            for ($i = 2; $i < $count; ++$i) {
+                list($key, $value) = explode('/', $agent[$i]);
+                $this->_javaInfo[$key] = $value;
+            }
+        } else {
+
+            // J-PHONE/2.0/J-DN02
+            @list($this->name, $this->version, $model) =
+                explode('/', $agent[0]);
+            $this->_model  = (string)$model;
+            if ($this->_model) {
+                if (preg_match('!V\d+([A-Z]+)!', $this->_model, $matches)) {
+                    $this->_vendor = $matches[1];
+                } elseif (preg_match('!J-([A-Z]+)!', $this->_model, $matches)) {
+                    $this->_vendor = $matches[1];
+                }
+            }
+        }
+    }
+
+    // }}}
+    // {{{ _parseMotorola()
+
+    /**
+     * parse HTTP_USER_AGENT string for the Motorola 3G aegnt
+     *
+     * @param array $agent parts of the User-Agent string
+     * @return mixed void, or a PEAR error object on error
+     */
+    function _parseMotorola(&$agent)
+    {
+        $count = count($agent);
+        $this->_packetCompliant = true;
+        $this->_vendor = 'MOT';
+
+        // MOT-V980/80.2F.2E. MIB/2.2.1 Profile/MIDP-2.0 Configuration/CLDC-1.1
+        list($name, $this->_vendorVersion) = explode('/', $agent[0]);
+        $this->_model = substr(strrchr($name, '-'), 1);
+
+        for ($i = 2; $i < $count; ++$i) {
+            list($key, $value) = explode('/', $agent[$i]);
+            $this->_javaInfo[$key] = $value;
+        }
+    }
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+
+/*
+ * Local Variables:
+ * mode: php
+ * coding: iso-8859-1
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * indent-tabs-mode: nil
+ * End:
+ */
+?>
Index: branches/comu/data/module/Net/UserAgent/Mobile.php
===================================================================
--- branches/comu/data/module/Net/UserAgent/Mobile.php	(revision 11984)
+++ branches/comu/data/module/Net/UserAgent/Mobile.php	(revision 11984)
@@ -0,0 +1,358 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+/**
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    CVS: $Id: Mobile.php,v 1.27 2007/02/20 15:17:16 kuboa Exp $
+ * @since      File available since Release 0.1
+ */
+
+require_once dirname(__FILE__) . '/../../PEAR.php';
+require_once dirname(__FILE__) . '/Mobile/Request.php';
+
+// {{{ constants
+
+/**
+ * Constants for error handling.
+ */
+define('NET_USERAGENT_MOBILE_OK',               1);
+define('NET_USERAGENT_MOBILE_ERROR',           -1);
+define('NET_USERAGENT_MOBILE_ERROR_NOMATCH',   -2);
+define('NET_USERAGENT_MOBILE_ERROR_NOT_FOUND', -3);
+
+// }}}
+// {{{ GLOBALS
+
+/**
+ * globals for fallback on no match
+ *
+ * @global boolean $GLOBALS['_NET_USERAGENT_MOBILE_FALLBACK_ON_NOMATCH']
+ */
+$GLOBALS['_NET_USERAGENT_MOBILE_FALLBACK_ON_NOMATCH'] = false;
+
+// }}}
+// {{{ Net_UserAgent_Mobile
+
+/**
+ * HTTP mobile user agent string parser
+ *
+ * Net_UserAgent_Mobile parses HTTP_USER_AGENT strings of (mainly Japanese)
+ * mobile HTTP user agents. It'll be useful in page dispatching by user
+ * agents.
+ * This package was ported from Perl's HTTP::MobileAgent.
+ * See {@link http://search.cpan.org/search?mode=module&query=HTTP-MobileAgent}
+ * The author of the HTTP::MobileAgent module is Tatsuhiko Miyagawa
+ * <miyagawa@bulknews.net>
+ *
+ * SYNOPSIS:
+ * <code>
+ * require_once 'Net/UserAgent/Mobile.php';
+ *
+ * $agent = &Net_UserAgent_Mobile::factory($agent_string);
+ * // or $agent = &Net_UserAgent_Mobile::factory(); // to get from $_SERVER
+ *
+ * if ($agent->isDoCoMo()) {
+ *     // or if ($agent->getName() == 'DoCoMo')
+ *     // or if (strtolower(get_class($agent)) == 'http_mobileagent_docomo')
+ *     // it's NTT DoCoMo i-mode
+ *     // see what's available in Net_UserAgent_Mobile_DoCoMo
+ * } elseif ($agent->isVodafone()) {
+ *     // it's Vodafone(J-PHONE)
+ *     // see what's available in Net_UserAgent_Mobile_Vodafone
+ * } elseif ($agent->isEZweb()) {
+ *     // it's KDDI/EZWeb
+ *     // see what's available in Net_UserAgent_Mobile_EZweb
+ * } else {
+ *     // may be PC
+ *     // $agent is Net_UserAgent_Mobile_NonMobile
+ * }
+ *
+ * $display = $agent->getDisplay();    // Net_UserAgent_Mobile_Display
+ * if ($display->isColor()) {
+ *    ...
+ * }
+ * </code>
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @since      Class available since Release 0.1
+ */
+class Net_UserAgent_Mobile
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     * @static
+     */
+
+    // }}}
+    // {{{ factory()
+
+    /**
+     * create a new {@link Net_UserAgent_Mobile_Common} subclass instance
+     *
+     * parses HTTP headers and constructs {@link Net_UserAgent_Mobile_Common}
+     * subclass instance.
+     * If no argument is supplied, $_SERVER{'HTTP_*'} is used.
+     *
+     * @param mixed $stuff User-Agent string or object that works with
+     *     HTTP_Request (not implemented)
+     * @return mixed a newly created Net_UserAgent_Mobile object, or a PEAR
+     *     error object on error
+     * @see Net_UserAgent_Mobile_Request::factory()
+     */
+    function &factory($stuff = null)
+    {
+        static $mobileRegex;
+        if (!isset($mobileRegex)) {
+            $docomoRegex    = '^DoCoMo/\d\.\d[ /]';
+            $vodafoneRegex  = '^(?:(?:SoftBank|Vodafone|J-PHONE|Vemulator|J-EMULATOR)/\d\.\d|(?:MOT|MOTEMULATOR)-)';
+            $ezwebRegex     = '^(?:KDDI-[A-Z]+\d+[A-Z]? )?UP\.Browser\/';
+            $airhphoneRegex = '^Mozilla/3\.0\((?:DDIPOCKET|WILLCOM);';
+            $mobileRegex =
+                "(?:($docomoRegex)|($vodafoneRegex)|($ezwebRegex)|($airhphoneRegex))";
+        }
+
+        $request = &Net_UserAgent_Mobile_Request::factory($stuff);
+
+        // parse User-Agent string
+        $ua = $request->get('User-Agent');
+        $sub = 'NonMobile';
+        if (preg_match("!$mobileRegex!", $ua, $matches)) {
+            $sub = @$matches[1] ? 'DoCoMo' :
+                (@$matches[2] ? 'Vodafone' :
+                 (@$matches[3] ? 'EZweb' : 'AirHPhone'));
+        }
+        $className = "Net_UserAgent_Mobile_{$sub}";
+
+        if (!class_exists($className)) {
+            $file = dirname(__FILE__) . "/Mobile/{$sub}.php";
+            if (!include_once $file) {
+                return PEAR::raiseError(null,
+                                        NET_USERAGENT_MOBILE_ERROR_NOT_FOUND,
+                                        null, null,
+                                        "Unable to include the $file file",
+                                        'Net_UserAgent_Mobile_Error', true
+                                        );
+            }
+        }
+
+        $instance = &new $className($request);
+        $error = &$instance->isError();
+        if (Net_UserAgent_Mobile::isError($error)) {
+            if ($GLOBALS['_NET_USERAGENT_MOBILE_FALLBACK_ON_NOMATCH']
+                && $error->getCode() == NET_USERAGENT_MOBILE_ERROR_NOMATCH
+                ) {
+                $instance = &Net_UserAgent_Mobile::factory('Net_UserAgent_Mobile_Fallback_On_NoMatch');
+                return $instance;
+            }
+
+            $instance = &$error;
+        }
+
+        return $instance;
+    }
+
+    // }}}
+    // {{{ singleton()
+
+    /**
+     * creates a new {@link Net_UserAgent_Mobile_Common} subclass instance or
+     * returns a instance from existent ones
+     *
+     * @param mixed $stuff User-Agent string or object that works with
+     *     HTTP_Request (not implemented)
+     * @return mixed a newly created or a existent Net_UserAgent_Mobile
+     *     object, or a PEAR error object on error
+     * @see Net_UserAgent_Mobile::factory()
+     */
+     function &singleton($stuff = null)
+     {
+         static $instance;
+         if (!isset($instance)) {
+             $instance = Net_UserAgent_Mobile::factory($stuff);
+         }
+
+         return $instance;
+     }
+
+    // }}}
+    // {{{ isError()
+
+    /**
+     * tell whether a result code from a Net_UserAgent_Mobile method
+     * is an error
+     *
+     * @param integer $value result code
+     * @return boolean whether $value is an {@link Net_UserAgent_Mobile_Error}
+     */
+    function isError($value)
+    {
+        return is_a($value, 'Net_UserAgent_Mobile_Error');
+    }
+
+    // }}}
+    // {{{ errorMessage()
+
+    /**
+     * return a textual error message for a Net_UserAgent_Mobile error code
+     *
+     * @param integer $value error code
+     * @return string error message, or false if the error code was not
+     *     recognized
+     */
+    function errorMessage($value)
+    {
+        static $errorMessages;
+        if (!isset($errorMessages)) {
+            $errorMessages = array(
+                                   NET_USERAGENT_MOBILE_ERROR           => 'unknown error',
+                                   NET_USERAGENT_MOBILE_ERROR_NOMATCH   => 'no match',
+                                   NET_USERAGENT_MOBILE_ERROR_NOT_FOUND => 'not found',
+                                   NET_USERAGENT_MOBILE_OK              => 'no error'
+                                   );
+        }
+
+        if (Net_UserAgent_Mobile::isError($value)) {
+            $value = $value->getCode();
+        }
+
+        return isset($errorMessages[$value]) ?
+            $errorMessages[$value] :
+            $errorMessages[NET_USERAGENT_MOBILE_ERROR];
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+// {{{ Net_UserAgent_Mobile_Error
+
+/**
+ * Net_UserAgent_Mobile_Error implements a class for reporting user
+ * agent error messages
+ *
+ * @category   Networking
+ * @package    Net_UserAgent_Mobile
+ * @author     KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @copyright  2003-2007 KUBO Atsuhiro <iteman@users.sourceforge.net>
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    Release: 0.30.0
+ * @since      Class available since Release 0.1
+ */
+class Net_UserAgent_Mobile_Error extends PEAR_Error
+{
+
+    // {{{ properties
+
+    /**#@+
+     * @access public
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    /**#@+
+     * @access public
+     */
+
+    // }}}
+    // {{{ constructor
+
+    /**
+     * constructor
+     *
+     * @param mixed   $code     Net_UserAgent_Mobile error code, or string
+     *     with error message.
+     * @param integer $mode     what 'error mode' to operate in
+     * @param integer $level    what error level to use for $mode and
+     *     PEAR_ERROR_TRIGGER
+     * @param mixed   $userinfo additional user/debug info
+     * @access public
+     */
+    function Net_UserAgent_Mobile_Error($code = NET_USERAGENT_MOBILE_ERROR,
+                                        $mode = PEAR_ERROR_RETURN,
+                                        $level = E_USER_NOTICE,
+                                        $userinfo = null
+                                        )
+    {
+        if (is_int($code)) {
+            $this->PEAR_Error('Net_UserAgent_Mobile Error: ' .
+                              Net_UserAgent_Mobile::errorMessage($code),
+                              $code, $mode, $level, $userinfo
+                              );
+        } else {
+            $this->PEAR_Error("Net_UserAgent_Mobile Error: $code",
+                              NET_USERAGENT_MOBILE_ERROR, $mode, $level,
+                              $userinfo
+                              );
+        }
+    }
+
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+
+    /**#@-*/
+
+    // }}}
+}
+
+// }}}
+
+/*
+ * Local Variables:
+ * mode: php
+ * coding: iso-8859-1
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * indent-tabs-mode: nil
+ * End:
+ */
+?>
