diff options
Diffstat (limited to 'phpBB')
31 files changed, 606 insertions, 1317 deletions
diff --git a/phpBB/adm/style/acp_jabber.html b/phpBB/adm/style/acp_jabber.html index 03992364dd..4d667d2966 100644 --- a/phpBB/adm/style/acp_jabber.html +++ b/phpBB/adm/style/acp_jabber.html @@ -38,10 +38,13 @@ <dt><label for="jab_password">{L_JAB_PASSWORD}:</label></dt> <dd><input type="password" id="jab_password" name="jab_password" value="{JAB_PASSWORD}" /></dd> </dl> +<!-- IF S_CAN_USE_SSL --> <dl> - <dt><label for="jab_resource">{L_JAB_RESOURCE}:</label><br /><span>{L_JAB_RESOURCE_EXPLAIN}</span></dt> - <dd><input type="text" id="jab_resource" name="jab_resource" value="{JAB_RESOURCE}" /></dd> + <dt><label for="jab_use_ssl">{L_JAB_USE_SSL}:</label><br /><span>{L_JAB_USE_SSL_EXPLAIN}</span></dt> + <dd><label><input type="radio" class="radio" id="jab_use_ssl" name="jab_use_ssl" value="1"<!-- IF JAB_USE_SSL --> checked="checked"<!-- ENDIF --> /> {L_YES}</label> + <label><input type="radio" class="radio" name="jab_use_ssl" value="0"<!-- IF not JAB_USE_SSL --> checked="checked"<!-- ENDIF --> /> {L_NO}</label></dd> </dl> +<!-- ENDIF --> <dl> <dt><label for="jab_package_size">{L_JAB_PACKAGE_SIZE}:</label><br /><span>{L_JAB_PACKAGE_SIZE_EXPLAIN}</span></dt> <dd><input type="text" id="jab_package_size" name="jab_package_size" value="{JAB_PACKAGE_SIZE}" maxlength="5" size="5" /></dd> diff --git a/phpBB/adm/style/acp_users.html b/phpBB/adm/style/acp_users.html index a7bde1e77a..307ddb75e4 100644 --- a/phpBB/adm/style/acp_users.html +++ b/phpBB/adm/style/acp_users.html @@ -173,7 +173,7 @@ <tbody> <!-- BEGIN attach --> <!-- IF attach.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF --> - <td><a href="{attach.U_DOWNLOAD}">{attach.REAL_FILENAME}</a><br /><span class="small"><!-- IF attach.S_IN_MESSAGE --><strong>{L_PM}: </strong><!-- ELSE --><strong>{L_TOPIC}: </strong><!-- ENDIF --><a href="{attach.U_VIEW_TOPIC}">{attach.TOPIC_TITLE}</a></span></td> + <td><a href="{attach.U_DOWNLOAD}">{attach.REAL_FILENAME}</a><br /><span class="small"><!-- IF attach.S_IN_MESSAGE --><strong>{L_PM}: </strong><!-- ELSE --><strong>{L_POST}: </strong><!-- ENDIF --><a href="{attach.U_VIEW_TOPIC}">{attach.TOPIC_TITLE}</a></span></td> <td style="text-align: center">{attach.POST_TIME}</td> <td style="text-align: center">{attach.SIZE}</td> <td style="text-align: center">{attach.DOWNLOAD_COUNT}</td> diff --git a/phpBB/adm/style/admin.css b/phpBB/adm/style/admin.css index 458cae5d97..8e924b1266 100644 --- a/phpBB/adm/style/admin.css +++ b/phpBB/adm/style/admin.css @@ -721,7 +721,7 @@ option { } option.disabled-option { - color: #aaa; + color: graytext; } .rtl option { diff --git a/phpBB/docs/AUTHORS b/phpBB/docs/AUTHORS index 02866d7dc1..769d25d9e8 100644 --- a/phpBB/docs/AUTHORS +++ b/phpBB/docs/AUTHORS @@ -46,7 +46,7 @@ Smarty (c) 2001, 2002 by ispi of Lincoln, Inc, http://smarty.php.net/ GPL licenced: phpMyAdmin (c) 2001,2003 phpMyAdmin Devel team, http://www.phpmyadmin.net/ -Jabber Class (c) 2004 Nathan Fritz, http://cjphp.netflint.net +Jabber Class (c) 2006 Flyspray.org, http://www.flyspray.org/ Chora (c) 2000-2006, The Horde Project. http://horde.org/chora/ Horde Project (c) 2000-2006, The Horde Project. http://horde.org/ diff --git a/phpBB/docs/CHANGELOG.html b/phpBB/docs/CHANGELOG.html index c21a5e4170..d830d88e21 100644 --- a/phpBB/docs/CHANGELOG.html +++ b/phpBB/docs/CHANGELOG.html @@ -218,6 +218,14 @@ p a { <li>[Fix] Do not use the gen_random_string function to create cookie names during install (Bug #11431)</li> <li>[Fix] Send stylesheet in style.php even without a valid session id (Bug #11531)</li> <li>[Fix] request_var should strictly return the requested number of dimensions</li> + <li>[Fix] Correct assignment of custom width to $user->img(); / Correctly display poll bars in subsilver2 (Bug #11301)</li> + <li>[Fix] Allow removing polls in prosilver</li> + <li>{Fix] Correct link to post in managing users attachments (Bug #11765)</li> + <li>[Fix] Reload confirm screen for selecting new forum for global topic type change if not postable forum is chosen (Bug #11711)</li> + <li>[Fix] Correctly show system default color for disabled options in Internet Explorer which does not support disabled option fields</li> + <li>[Fix] Update query for custom profiles in user management used wrong order for left/right delimiter (affecting mssql) (Bug #11781)</li> + <li>[Feature] Replaced outdated jabber class with the one from the flyspray project</li> + <li>Limit maximum number of allowed characters in messages to 60.000 by default. Admins should increase their PHP time limits if they want to raise this tremedously.</li> </ul> </div> diff --git a/phpBB/includes/acp/acp_jabber.php b/phpBB/includes/acp/acp_jabber.php index d58fef14f1..a5bcecb329 100644 --- a/phpBB/includes/acp/acp_jabber.php +++ b/phpBB/includes/acp/acp_jabber.php @@ -41,121 +41,59 @@ class acp_jabber $jab_port = request_var('jab_port', $config['jab_port']); $jab_username = request_var('jab_username', $config['jab_username']); $jab_password = request_var('jab_password', $config['jab_password']); - $jab_resource = request_var('jab_resource', $config['jab_resource']); $jab_package_size = request_var('jab_package_size', $config['jab_package_size']); + $jab_use_ssl = request_var('jab_use_ssl', $config['jab_use_ssl']); - $jabber = new jabber($jab_host, $jab_port, $jab_username, $jab_password, $jab_resource); - $error = array(); - - $message = $user->lang['JAB_SETTINGS_CHANGED']; - $log = 'JAB_SETTINGS_CHANGED'; - - // Are changing (or initialising) a new host or username? If so run some checks and - // try to create account if it doesn't exist - if ($jab_enable) + if ($submit) { - if (($jab_host != $config['jab_host'] || $jab_username != $config['jab_username']) && $jab_username) - { - if (!$jabber->connect()) - { - trigger_error($user->lang['ERR_JAB_CONNECT'] . $jabber->get_log() . adm_back_link($this->u_action), E_USER_WARNING); - } + $error = array(); - // First we'll try to authorise using this account, if that fails we'll try to create it. - if (!($result = $jabber->send_auth())) - { - if (($result = $jabber->account_registration($config['board_email'], $config['sitename'])) <> 2) - { - $error[] = ($result == 1) ? $user->lang['ERR_JAB_USERNAME'] : sprintf($user->lang['ERR_JAB_REGISTER'], $result); - } - else - { - $message = $user->lang['JAB_REGISTERED']; - $log = 'JAB_REGISTER'; - } - } - else - { - $message = $user->lang['JAB_CHANGED']; - $log = 'JAB_CHANGED'; - } + $message = $user->lang['JAB_SETTINGS_CHANGED']; + $log = 'JAB_SETTINGS_CHANGED'; - sleep(1); - $jabber->disconnect(); - } - else if ($jab_password != $config['jab_password']) + // Is this feature enabled? Then try to establish a connection + if ($jab_enable) { + $jabber = new jabber($jab_host, $jab_port, $jab_username, $jab_password); + if (!$jabber->connect()) { trigger_error($user->lang['ERR_JAB_CONNECT'] . $jabber->get_log() . adm_back_link($this->u_action), E_USER_WARNING); } - if (!$jabber->send_auth()) + // We'll try to authorise using this account + if (!$jabber->login()) { trigger_error($user->lang['ERR_JAB_AUTH'] . $jabber->get_log() . adm_back_link($this->u_action), E_USER_WARNING); } - $jabber->send_presence(NULL, NULL, 'online'); - if (($result = $jabber->change_password($jab_password)) <> 2) - { - $error[] = ($result == 1) ? $user->lang['ERR_JAB_PASSCHG'] : sprintf($user->lang['ERR_JAB_PASSFAIL'], $result); - } - else - { - $message = $user->lang['JAB_PASS_CHANGED']; - $log = 'JAB_PASSCHG'; - } - - sleep(1); $jabber->disconnect(); } - } - // Pull relevant config data - $sql = 'SELECT * - FROM ' . CONFIG_TABLE . " - WHERE config_name LIKE 'jab_%'"; - $result = $db->sql_query($sql); + set_config('jab_enable', $jab_enable); + set_config('jab_host', $jab_host); + set_config('jab_port', $jab_port); + set_config('jab_username', $jab_username); + set_config('jab_password', $jab_password); + set_config('jab_package_size', $jab_package_size); + set_config('jab_use_ssl', $jab_use_ssl); - while ($row = $db->sql_fetchrow($result)) - { - $config_name = $row['config_name']; - $config_value = $row['config_value']; - - $default_config[$config_name] = $config_value; - $new[$config_name] = (isset($_POST[$config_name])) ? request_var($config_name, '') : $default_config[$config_name]; - - if ($submit && !sizeof($error)) - { - set_config($config_name, $new[$config_name]); - } - } - - if ($submit && !sizeof($error)) - { add_log('admin', 'LOG_' . $log); trigger_error($message . adm_back_link($this->u_action)); } - if (sizeof($error)) - { - $template->assign_vars(array( - 'S_WARNING' => true, - 'WARNING_MSG' => implode('<br />', $error)) - ); - } - $template->assign_vars(array( 'U_ACTION' => $this->u_action, - 'JAB_ENABLE' => $new['jab_enable'], + 'JAB_ENABLE' => $jab_enable, 'L_JAB_SERVER_EXPLAIN' => sprintf($user->lang['JAB_SERVER_EXPLAIN'], '<a href="http://www.jabber.org/">', '</a>'), - 'JAB_HOST' => $new['jab_host'], - 'JAB_PORT' => $new['jab_port'], - 'JAB_USERNAME' => $new['jab_username'], - 'JAB_PASSWORD' => $new['jab_password'], - 'JAB_RESOURCE' => $new['jab_resource'], - 'JAB_PACKAGE_SIZE' => $new['jab_package_size']) - ); + 'JAB_HOST' => $jab_host, + 'JAB_PORT' => $jab_port, + 'JAB_USERNAME' => $jab_username, + 'JAB_PASSWORD' => $jab_password, + 'JAB_PACKAGE_SIZE' => $jab_package_size, + 'JAB_USE_SSL' => $jab_use_ssl, + 'S_CAN_USE_SSL' => jabber::can_use_ssl(), + )); } } diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index 0a09926156..231c21252e 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -1067,7 +1067,7 @@ class acp_users foreach ($cp_data as $key => $value) { - $cp_data[$right_delim . $key . $left_delim] = $value; + $cp_data[$left_delim . $key . $right_delim] = $value; unset($cp_data[$key]); } @@ -1616,7 +1616,7 @@ class acp_users } else { - $view_topic = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row['topic_id']}&p={$row['post_msg_id']}#{$row['post_msg_id']}"); + $view_topic = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row['topic_id']}&p={$row['post_msg_id']}") . '#p' . $row['post_msg_id']; } $template->assign_block_vars('attach', array( diff --git a/phpBB/includes/functions_jabber.php b/phpBB/includes/functions_jabber.php index 3872346bbc..3ad96df928 100644 --- a/phpBB/includes/functions_jabber.php +++ b/phpBB/includes/functions_jabber.php @@ -10,665 +10,212 @@ /** * -* Class.Jabber.PHP v0.4.2 -* (c) 2004 Nathan "Fritzy" Fritz -* http://cjphp.netflint.net *** fritzy@netflint.net +* Jabber class from Flyspray project +* @version class.jabber2.php 1209 2007-05-12 13:39:10Z floele +* @copyright 2006 Flyspray.org +* @author: Florian Schmitz (floele) * -* This is a bugfix version, specifically for those who can't get -* 0.4 to work on Jabberd2 servers. -* -* last modified: 24.03.2004 13:01:53 -* -* Modified by phpBB Development Team -* version: v0.4.3 +* Modified by Acyd Burn * * @package phpBB3 */ class jabber { + var $connection = null; + var $session = array(); + var $timeout = 10; + var $server; var $port; var $username; var $password; - var $resource; - var $jid; - - var $connection; - var $delay_disconnect; - - var $stream_id; + var $use_ssl; var $enable_logging; var $log_array; - var $iq_sleep_timer; - var $last_ping_time; - - var $packet_queue; - - var $iq_version_name; - var $iq_version_os; - var $iq_version_version; - - var $error_codes; - - var $connected; - var $keep_alive_id; - var $returned_keep_alive; - var $txnid; - - var $connector; + var $features = array(); - var $version; - var $show_version; - - /** - * Constructor - */ - function jabber($server, $port, $username, $password, $resource) + function jabber($server, $port, $username, $password, $use_ssl = false) { $this->server = ($server) ? $server : 'localhost'; - $this->port = ($port) ? $port : '5222'; + $this->port = ($port) ? $port : 5222; $this->username = $username; $this->password = $password; - $this->resource = ($resource) ? $resource : NULL; - - $this->enable_logging = true; - $this->log_array = array(); + $this->use_ssl = ($use_ssl && $this->can_use_ssl) ? true : false; - $this->version = '1.0'; - $this->show_version = false; - - $this->packet_queue = array(); - $this->iq_sleep_timer = $this->delay_disconnect = 1; - - $this->returned_keep_alive = true; - $this->txnid = 0; - - $this->iq_version_name = "Class.Jabber.PHP -- http://cjphp.netflint.net -- by Nathan 'Fritzy' Fritz, fritz@netflint.net"; - $this->iq_version_version = '0.4'; - $this->iq_version_os = $_SERVER['SERVER_SOFTWARE']; - - $this->error_codes = array( - 400 => 'Bad Request', - 401 => 'Unauthorised', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Registration Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Remove Server Error', - 503 => 'Service Unavailable', - 504 => 'Remove Server Timeout', - 510 => 'Disconnected' - ); - } - - /** - * Connect - */ - function connect() - { - $this->connector = new cjp_standard_connector; - - if ($this->connector->open_socket($this->server, $this->port)) + // Change port if we use SSL + if ($this->port == 5222 && $this->use_ssl) { - $this->send_packet("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); - $this->send_packet("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'" . (($this->show_version) ? " version='{$this->version}'" : '') . ">\n"); - - sleep(2); - - if ($this->_check_connected()) - { - $this->connected = true; // Nathan Fritz - return true; - } - else - { - $this->add_to_log('ERROR: connect() #1'); - return false; - } + $this->port = 5223; } - else - { - $this->add_to_log('ERROR: connect() #2'); - return false; - } - } - - /** - * Disconnect - */ - function disconnect() - { - if (is_int($this->delay_disconnect)) - { - sleep($this->delay_disconnect); - } - - $this->send_packet('</stream:stream>'); - $this->connector->close_socket(); - } - - /** - * Send authentication request - */ - function send_auth() - { - $this->auth_id = 'auth_' . md5(time() . $_SERVER['REMOTE_ADDR']); - $this->resource = ($this->resource != NULL) ? $this->resource : ('Class.Jabber.PHP ' . md5($this->auth_id)); - $this->jid = "{$this->username}@{$this->server}/{$this->resource}"; - - // request available authentication methods - $payload = "<username>{$this->username}</username>"; - $packet = $this->send_iq(NULL, 'get', $this->auth_id, 'jabber:iq:auth', $payload); - - // was a result returned? - if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) - { - // yes, now check for auth method availability in descending order (best to worst) - if (isset($packet['iq']['#']['query'][0]['#']['sequence'][0]['#']) && isset($packet['iq']['#']['query'][0]['#']['token'][0]['#'])) - { - // auth_0k - return $this->_sendauth_ok($packet['iq']['#']['query'][0]['#']['token'][0]['#'], $packet['iq']['#']['query'][0]['#']['sequence'][0]['#']); - } - else if (isset($packet['iq']['#']['query'][0]['#']['digest'])) - { - // digest - return $this->_sendauth_digest(); - } - else if ($packet['iq']['#']['query'][0]['#']['password']) - { - // plain text - return $this->_sendauth_plaintext(); - } - else - { - $this->add_to_log('ERROR: send_auth() #2 - No auth method available!'); - return false; - } - } - else - { - // no result returned - $this->add_to_log('ERROR: send_auth() #1'); - return false; - } - } - - /** - * Register account - */ - function account_registration($reg_email = NULL, $reg_name = NULL) - { - $packet = $this->send_iq($this->server, 'get', 'reg_01', 'jabber:iq:register'); - - if ($packet) - { - // just in case a key was passed back from the server - $key = $this->get_info_from_iq_key($packet); - unset($packet); - - $payload = "<username>{$this->username}</username> - <password>{$this->password}</password> - <email>$reg_email</email> - <name>$reg_name</name>\n"; - - $payload .= ($key) ? "<key>$key</key>\n" : ''; - $packet = $this->send_iq($this->server, 'set', 'reg_01', 'jabber:iq:register', $payload); - - if ($this->get_info_from_iq_type($packet) == 'result') - { - $return_code = (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) ? 1 : 2; - $this->jid = ($this->resource) ? "{$this->username}@{$this->server}/{$this->resource}" : "{$this->username}@{$this->server}"; - } - else if ($this->get_info_from_iq_type($packet) == 'error' && isset($packet['iq']['#']['error'][0]['#'])) - { - // "conflict" error, i.e. already registered - if ($packet['iq']['#']['error'][0]['@']['code'] == '409') - { - $return_code = 1; - } - else - { - $return_code = 'Error ' . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; - } - } - - return $return_code; - } - else - { - return 3; - } + $this->enable_logging = true; + $this->log_array = array(); } /** - * Change password + * Able to use the SSL functionality? */ - function change_password($new_password) + function can_use_ssl() { - $packet = $this->send_iq($this->server, 'get', 'A0', 'jabber:iq:register'); - - if ($packet) - { - // just in case a key was passed back from the server - $key = $this->get_info_from_iq_key($packet); - unset($packet); - - $payload = "<username>{$this->username}</username> - <password>{$new_password}</password>\n"; - $payload .= ($key) ? "<key>$key</key>\n" : ''; - - $packet = $this->send_iq($this->server, 'set', 'A0', 'jabber:iq:register', $payload); - - if ($this->get_info_from_iq_type($packet) == 'result') - { - $return_code = (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) ? 1 : 2; - } - else if ($this->get_info_from_iq_type($packet) == 'error' && isset($packet['iq']['#']['error'][0]['#'])) - { - // "conflict" error, i.e. already registered - if ($packet['iq']['#']['error'][0]['@']['code'] == '409') - { - $return_code = 1; - } - else - { - $return_code = 'Error ' . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; - } - } - - return $return_code; - } - else - { - return 3; - } + // Will not work with PHP >= 5.2.1 until timeout problem with ssl hasn't been fixed (http://bugs.php.net/41236) + return (version_compare(PHP_VERSION, '5.2.1', '<') && @extension_loaded('openssl')) ? true : false; } /** - * Send packet + * Able to use TLS? */ - function send_packet($xml) + function can_use_tls() { - $xml = trim($xml); - - if ($this->connector->write_to_socket($xml)) + if (!@extension_loaded('openssl') || !function_exists('stream_socket_enable_crypto') || !function_exists('stream_get_meta_data') || !function_exists('socket_set_blocking') || !function_exists('stream_get_wrappers')) { - $this->add_to_log('SEND: ' . $xml); - return true; - } - else - { - $this->add_to_log('ERROR: send_packet() #1'); return false; } - } - - /** - * Listen to socket - */ - function listen() - { - $incoming = ''; - - while ($line = $this->connector->read_from_socket(4096)) - { - $incoming .= $line; - } - $incoming = trim($incoming); + // Make sure the encryption stream is supported + $streams = stream_get_wrappers(); - if ($incoming != '') + if (!in_array('streams.crypto', $streams)) { - $this->add_to_log('RECV: ' . $incoming); - $temp = $this->_split_incoming($incoming); - - for ($i = 0, $size = sizeof($temp); $i < $size; $i++) - { - $this->packet_queue[] = $this->xmlize($temp[$i]); - } + return false; } return true; } /** - * Strip jid - */ - function strip_jid($jid = NULL) - { - preg_match('#(.*)\/(.*)#Ui', $jid, $temp); - return ($temp[1] != '') ? $temp[1] : $jid; - } - - /** - * Send a message + * Connect */ - function send_message($to, $type = 'normal', $id = NULL, $content = NULL, $payload = NULL) + function connect() { - if ($to && is_array($content)) - { - if (!$id) - { - $id = $type . '_' . time(); - } - - $this->_array_xmlspecialchars($content); - - $xml = "<message to='$to' type='$type' id='$id'>\n"; - - if (!empty($content['subject'])) - { - $xml .= '<subject>' . $content['subject'] . "</subject>\n"; - } - - if (!empty($content['thread'])) - { - $xml .= '<thread>' . $content['thread'] . "</thread>\n"; - } - - $xml .= '<body>' . $content['body'] . "</body>\n"; - $xml .= $payload; - $xml .= "</message>\n"; - - if ($this->send_packet($xml)) - { - return true; - } - else - { - $this->add_to_log('ERROR: send_message() #1'); - } - } - else +/* if (!$this->check_jid($this->username . '@' . $this->server)) { - $this->add_to_log('ERROR: send_message() #2'); + $this->add_to_log('Error: Jabber ID is not valid: ' . $this->username . '@' . $this->server); return false; - } - } - - /** - * Send presence - */ - function send_presence($type = NULL, $to = NULL, $status = NULL, $show = NULL, $priority = NULL) - { - $xml = '<presence'; - $xml .= ($to) ? " to='$to'" : ''; - $xml .= ($type) ? " type='$type'" : ''; - $xml .= ($status || $show || $priority) ? ">\n" : " />\n"; - - $xml .= ($status) ? " <status>$status</status>\n" : ''; - $xml .= ($show) ? " <show>$show</show>\n" : ''; - $xml .= ($priority) ? " <priority>$priority</priority>\n" : ''; + }*/ - $xml .= ($status || $show || $priority) ? "</presence>\n" : ''; + $this->session['ssl'] = $this->use_ssl; - if ($this->send_packet($xml)) + if ($this->open_socket($this->server, $this->port, $this->use_ssl)) { - return true; + $this->send("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); + $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); } else { - $this->add_to_log('ERROR: send_presence() #1'); + $this->add_to_log('Error: connect() #2'); return false; } - } - - /** - * Send error - */ - function send_error($to, $id = NULL, $error_number, $error_message = NULL) - { - $xml = "<iq type='error' to='$to'"; - $xml .= ($id) ? " id='$id'" : ''; - $xml .= ">\n"; - $xml .= " <error code='$error_number'>"; - $xml .= ($error_message) ? $error_message : $this->error_codes[$error_number]; - $xml .= "</error>\n"; - $xml .= '</iq>'; - - $this->send_packet($xml); - } - /** - * Get first from queue - */ - function get_first_from_queue() - { - return array_shift($this->packet_queue); + // Now we listen what the server has to say...and give appropriate responses + $this->response($this->listen()); + return true; } /** - * Get from queue by id + * Disconnect */ - function get_from_queue_by_id($packet_type, $id) + function disconnect() { - $found_message = false; - - foreach ($this->packet_queue as $key => $value) + if ($this->connected()) { - if ($value[$packet_type]['@']['id'] == $id) + // disconnect gracefully + if (isset($this->session['sent_presence'])) { - $found_message = $value; - unset($this->packet_queue[$key]); - - break; + $this->presence('offline', '', true); } + + $this->send('</stream:stream>'); + $this->session = array(); + return fclose($this->connection); } - return (is_array($found_message)) ? $found_message : false; + return false; } /** - * Call handler + * Connected? */ - function call_handler($packet = NULL) + function connected() { - $packet_type = $this->_get_packet_type($packet); - - if ($packet_type == 'message') - { - $type = $packet['message']['@']['type']; - $type = ($type != '') ? $type : 'normal'; - $funcmeth = "handler_message_$type"; - } - else if ($packet_type == 'iq') - { - $namespace = $packet['iq']['#']['query'][0]['@']['xmlns']; - $namespace = str_replace(':', '_', $namespace); - $funcmeth = "handler_iq_$namespace"; - } - else if ($packet_type == 'presence') - { - $type = $packet['presence']['@']['type']; - $type = ($type != '') ? $type : 'available'; - $funcmeth = "handler_presence_$type"; - } - - if ($funcmeth != '') - { - if (function_exists($funcmeth)) - { - call_user_func($funcmeth, $packet); - } - else if (method_exists($this, $funcmeth)) - { - call_user_func(array(&$this, $funcmeth), $packet); - } - else - { - $this->handler_not_implemented($packet); - $this->add_to_log("ERROR: call_handler() #1 - neither method nor function $funcmeth() available"); - } - } + return (is_resource($this->connection) && !feof($this->connection)) ? true : false; } + /** - * Cruise Control + * Initiates login (using data from contructor, after calling connect()) + * @access public + * @return bool */ - function cruise_control($seconds = -1) + function login() { - $count = 0; - - while ($count != $seconds) + if (!sizeof($this->features)) { - $this->listen(); - - do - { - $packet = $this->get_first_from_queue(); - - if ($packet) - { - $this->call_handler($packet); - } - } - while (sizeof($this->packet_queue) > 1); - - $count += 0.25; - usleep(250000); - - if (($this->last_ping_time + 180) < time()) - { - // Modified by Nathan Fritz - if ($this->returned_keep_alive == false) - { - $this->connected = false; - $this->add_to_log('EVENT: Disconnected'); - } - - if ($this->returned_keep_alive == true) - { - $this->connected = true; - } - - $this->returned_keep_alive = false; - - $this->keep_alive_id = 'keep_alive_' . time(); - // $this->send_packet("<iq id='{$this->keep_alive_id}'/>", 'cruise_control'); - $this->send_packet("<iq type='get' from='{$this->username}@{$this->server}/{$this->resource}' to='{$this->server}' id='{$this->keep_alive_id}'><query xmlns='jabber:iq:time' /></iq>"); - $this->last_ping_time = time(); - } + $this->add_to_log('Error: No feature information from server available.'); + return false; } - return true; + return $this->response($this->features); } /** - * Send iq + * Send data to the Jabber server + * @param string $xml + * @access public + * @return bool */ - function send_iq($to = NULL, $type = 'get', $id = NULL, $xmlns = NULL, $payload = NULL, $from = NULL) + function send($xml) { - if (!preg_match('#^(get|set|result|error)$#', $type)) + if ($this->connected()) { - unset($type); - - $this->add_to_log("ERROR: send_iq() #2 - type must be 'get', 'set', 'result' or 'error'"); - return false; - } - else if ($id && $xmlns) - { - $xml = "<iq type='$type' id='$id'"; - $xml .= ($to) ? " to='" . htmlspecialchars($to) . "'" : ''; - $xml .= ($from) ? " from='$from'" : ''; - $xml .= "> - <query xmlns='$xmlns'> - $payload - </query> - </iq>"; - - $this->send_packet($xml); - sleep($this->iq_sleep_timer); - $this->listen(); - - return (preg_match('#^(get|set)$#', $type)) ? $this->get_from_queue_by_id('iq', $id) : true; + $xml = trim($xml); + $this->add_to_log('SEND: '. $xml); + return fwrite($this->connection, $xml); } else { - $this->add_to_log('ERROR: send_iq() #1 - to, id and xmlns are mandatory'); + $this->add_to_log('Error: Could not send, connection lost (flood?).'); return false; } } /** - * get the transport registration fields - * method written by Steve Blinch, http://www.blitzaffe.com + * OpenSocket + * @param string $server host to connect to + * @param int $port port number + * @param bool $use_ssl use ssl or not + * @access public + * @return bool */ - function transport_registration_details($transport) + function open_socket($server, $port, $use_ssl = false) { - $this->txnid++; - $packet = $this->send_iq($transport, 'get', "reg_{$this->txnid}", 'jabber:iq:register', NULL, $this->jid); - - if ($packet) + if (@function_exists('dns_get_record')) { - $res = array(); - - foreach ($packet['iq']['#']['query'][0]['#'] as $element => $data) + $record = dns_get_record("_xmpp-client._tcp.$server", DNS_SRV); + if (!empty($record)) { - if ($element != 'instructions' && $element != 'key') - { - $res[] = $element; - } + $server = $record[0]['target']; } - - return $res; } else { - return 3; + $this->add_to_log('Warning: dns_get_record function not found. GTalk will not work.'); } - } - /** - * register with the transport - * method written by Steve Blinch, http://www.blitzaffe.com - */ - function transport_registration($transport, $details) - { - $this->txnid++; - $packet = $this->send_iq($transport, 'get', "reg_{$this->txnid}", 'jabber:iq:register', NULL, $this->jid); + $server = $use_ssl ? 'ssl://' . $server : $server; - if ($packet) + if ($this->connection = @fsockopen($server, $port, $errorno, $errorstr, $this->timeout)) { - // just in case a key was passed back from the server - $key = $this->get_info_from_iq_key($packet); - unset($packet); - - $payload = ($key) ? "<key>$key</key>\n" : ''; - foreach ($details as $element => $value) - { - $payload .= "<$element>$value</$element>\n"; - } - - $packet = $this->send_iq($transport, 'set', "reg_{$this->txnid}", 'jabber:iq:register', $payload); - - if ($this->get_info_from_iq_type($packet) == 'result') - { - $return_code = (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) ? 1 : 2; - } - else if ($this->get_info_from_iq_type($packet) == 'error') - { - if (isset($packet['iq']['#']['error'][0]['#'])) - { - $return_code = 'Error ' . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; - $this->add_to_log('ERROR: transport_registration()'); - } - } + socket_set_blocking($this->connection, 0); + socket_set_timeout($this->connection, 60); - return $return_code; - } - else - { - return 3; + return true; } + + // Apparently an error occured... + $this->add_to_log('Error: open_socket() - ' . $errorstr); + return false; } /** @@ -678,7 +225,7 @@ class jabber { if ($this->enable_logging && sizeof($this->log_array)) { - return implode("<br /><br />", $this->log_array); + return '<br /><br />' . implode("<br /><br />", $this->log_array); } return ''; @@ -691,640 +238,483 @@ class jabber { if ($this->enable_logging) { - $this->log_array[] = htmlspecialchars($string); + $this->log_array[] = utf8_htmlspecialchars($string); } } - - // ====================================================================== - // private methods - // ====================================================================== - /** - * Send auth - * @access private + * Listens to the connection until it gets data or the timeout is reached. + * Thus, it should only be called if data is expected to be received. + * @access public + * @return mixed either false for timeout or an array with the received data */ - function _sendauth_ok($zerok_token, $zerok_sequence) + function listen($timeout = 10, $wait = false) { - // initial hash of password - $zerok_hash = sha1($this->password); - - // sequence 0: hash of hashed-password and token - $zerok_hash = sha1($zerok_hash . $zerok_token); - - // repeat as often as needed - for ($i = 0; $i < $zerok_sequence; $i++) + if (!$this->connected()) { - $zerok_hash = sha1($zerok_hash); + return false; } - $payload = "<username>{$this->username}</username> - <hash>$zerok_hash</hash> - <resource>{$this->resource}</resource>"; - - $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); + // Wait for a response until timeout is reached + $start = time(); + $data = ''; - // was a result returned? - if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) + do { - return true; + $read = trim(fread($this->connection, 4096)); + $data .= $read; } - else - { - $this->add_to_log('ERROR: _sendauth_ok() #1'); - return false; - } - } + while (time() <= $start + $timeout && ($wait || $data == '' || $read != '' || (substr(rtrim($data), -1) != '>'))); - /** - * Send auth digest - * @access private - */ - function _sendauth_digest() - { - $payload = "<username>{$this->username}</username> - <resource>{$this->resource}</resource> - <digest>" . sha1($this->stream_id . $this->password) . "</digest>"; - - $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); - - // was a result returned? - if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) + if ($data != '') { - return true; + $this->add_to_log('RECV: '. $data); + return $this->xmlize($data); } else { - $this->add_to_log('ERROR: _sendauth_digest() #1'); + $this->add_to_log('Timeout, no response from server.'); return false; } } /** - * Send auth plain - * @access private + * Initiates account registration (based on data used for contructor) + * @access public + * @return bool */ - function _sendauth_plaintext() + function register() { - $payload = "<username>{$this->username}</username> - <password>{$this->password}</password> - <resource>{$this->resource}</resource>"; - - $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); - - // was a result returned? - if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) - { - return true; - } - else + if (!isset($this->session['id']) || isset($this->session['jid'])) { - $this->add_to_log('ERROR: _sendauth_plaintext() #1'); + $this->add_to_log('Error: Cannot initiate registration.'); return false; } + + $this->send("<iq type='get' id='reg_1'><query xmlns='jabber:iq:register'/></iq>"); + return $this->response($this->listen()); } /** - * Listen on socket - * @access private + * Sets account presence. No additional info required (default is "online" status) + * @param $message online, offline... + * @param $type dnd, away, chat, xa or nothing + * @access public + * @return bool */ - function _listen_incoming() + function send_presence($message = '', $type = '', $unavailable = false) { - $incoming = ''; - - while ($line = $this->connector->read_from_socket(4096)) + if (!isset($this->session['jid'])) { - $incoming .= $line; - } - - $incoming = trim($incoming); - - if ($incoming != '') - { - $this->add_to_log('RECV: ' . $incoming); + $this->add_to_log('ERROR: send_presence() - Cannot set presence at this point, no jid given.'); + return false; } - return $this->xmlize($incoming); - } + $type = strtolower($type); + $type = (in_array($type, array('dnd', 'away', 'chat', 'xa'))) ? '<show>'. $type .'</show>' : ''; - /** - * Check if connected - * @access private - */ - function _check_connected($in_tls = false) - { - $incoming_array = $this->_listen_incoming(); - - if (is_array($incoming_array)) - { - if ($incoming_array['stream:stream']['@']['from'] == $this->server && $incoming_array['stream:stream']['@']['xmlns'] == 'jabber:client' && $incoming_array['stream:stream']['@']['xmlns:stream'] == 'http://etherx.jabber.org/streams') - { - $this->stream_id = $incoming_array['stream:stream']['@']['id']; + $unavailable = ($unavailable) ? " type='unavailable'" : ''; + $message = ($message) ? '<status>' . utf8_htmlspecialchars($message) .'</status>' : ''; - // We only start TLS authentication if not called within TLS authentication itself, which may produce a never ending loop... - if (!$in_tls) - { - if (!empty($incoming_array['stream:stream']['#']['stream:features'][0]['#']['starttls'][0]['@']['xmlns']) && $incoming_array['stream:stream']['#']['stream:features'][0]['#']['starttls'][0]['@']['xmlns'] == 'urn:ietf:params:xml:ns:xmpp-tls') - { - return $this->_starttls(); - } - } + $this->session['sent_presence'] = !$unavailable; - return true; - } - else - { - $this->add_to_log('ERROR: _check_connected() #1'); - return false; - } - } - else - { - $this->add_to_log('ERROR: _check_connected() #2'); - return false; - } + return $this->send("<presence$unavailable>" . $type . $message . '</presence>'); } /** - * Start TLS/SSL session if supported (PHP5.1) - * @access private + * This handles all the different XML elements + * @param array $xml + * @access public + * @return bool */ - function _starttls() + function response($xml) { - if (!function_exists('stream_socket_enable_crypto') || !function_exists('stream_get_meta_data') || !function_exists('socket_set_blocking') || !function_exists('stream_get_wrappers')) + if (!is_array($xml) || !sizeof($xml)) { - $this->add_to_log('WARNING: TLS is not available'); - return true; - } - - // Make sure the encryption stream is supported - $streams = stream_get_wrappers(); - - if (!in_array('streams.crypto', $streams)) - { - $this->add_to_log('WARNING: SSL/crypto stream not supported'); - return true; - } - - $this->send_packet("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n"); - sleep(2); - $incoming_array = $this->_listen_incoming(); - - if (!is_array($incoming_array)) - { - $this->add_to_log('ERROR: _starttls() #1'); - return false; - } - - if ($incoming_array['proceed']['@']['xmlns'] != 'urn:ietf:params:xml:ns:xmpp-tls') - { - $this->add_to_log('ERROR: _starttls() #2'); return false; } - $meta = stream_get_meta_data($this->connector->active_socket); - socket_set_blocking($this->connector->active_socket, 1); - - $result = @stream_socket_enable_crypto($this->connector->active_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); - if (!$result) + // did we get multiple elements? do one after another + // array('message' => ..., 'presence' => ...) + if (sizeof($xml) > 1) { - socket_set_blocking($this->connector->active_socket, $meta['blocked']); - $this->add_to_log('ERROR: _starttls() #3'); - return false; + foreach ($xml as $key => $value) + { + $this->response(array($key => $value)); + } + return; } - - socket_set_blocking($this->connector->active_socket, $meta['blocked']); - - $this->send_packet("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); - $this->send_packet("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'" . (($this->show_version) ? " version='{$this->version}'" : '') . ">\n"); - sleep(2); - - if (!$this->_check_connected(true)) + else { - $this->add_to_log('ERROR: _starttls() #4'); - return false; + // or even multiple elements of the same type? + // array('message' => array(0 => ..., 1 => ...)) + if (sizeof(reset($xml)) > 1) + { + foreach (reset($xml) as $value) + { + $this->response(array(key($xml) => array(0 => $value))); + } + return; + } } - return true; - } - - /** - * Get packet type - * @access private - */ - function _get_packet_type($packet = NULL) - { - if (is_array($packet)) + switch (key($xml)) { - reset($packet); - $packet_type = key($packet); - } - - return ($packet_type) ? $packet_type : false; - } + case 'stream:stream': + // Connection initialised (or after authentication). Not much to do here... + $this->session['id'] = $xml['stream:stream'][0]['@']['id']; - /** - * Split incoming packet - * @access private - */ - function _split_incoming($incoming) - { - $temp = preg_split('#<(message|iq|presence|stream)#', $incoming, -1, PREG_SPLIT_DELIM_CAPTURE); - $array = array(); - - for ($i = 1, $size = sizeof($temp); $i < $size; $i += 2) - { - $array[] = '<' . $temp[$i] . $temp[($i + 1)]; - } - - return $array; - } - - /** - * Recursively prepares the strings in an array to be used in XML data. - * @access private - */ - function _array_xmlspecialchars(&$array) - { - if (is_array($array)) - { - foreach ($array as $k => $v) - { - if (is_array($v)) + if (isset($xml['stream:stream'][0]['#']['stream:features'])) { - $this->_array_xmlspecialchars($array[$k]); + // we already got all info we need + $this->features = $xml['stream:stream'][0]['#']; } else { - $this->_xmlspecialchars($array[$k]); + $this->features = $this->listen(); } - } - } - } - - /** - * Prepares a string for usage in XML data. - * @access private - */ - function _xmlspecialchars(&$string) - { - // we only have a few entities in xml - $string = str_replace(array('&', '>', '<', '"', '\''), array('&', '>', '<', '"', '''), $string); - } - - // ====================================================================== - // <message/> parsers - // ====================================================================== - - /** - * Get info from message (from) - */ - function get_info_from_message_from($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['@']['from'] : false; - } - - /** - * Get info from message (type) - */ - function get_info_from_message_type($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['@']['type'] : false; - } - - /** - * Get info from message (id) - */ - function get_info_from_message_id($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['@']['id'] : false; - } - - /** - * Get info from message (thread) - */ - function get_info_from_message_thread($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['#']['thread'][0]['#'] : false; - } - /** - * Get info from message (subject) - */ - function get_info_from_message_subject($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['#']['subject'][0]['#'] : false; - } - - /** - * Get info from message (body) - */ - function get_info_from_message_body($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['#']['body'][0]['#'] : false; - } - - /** - * Get info from message (xmlns) - */ - function get_info_from_message_xmlns($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['#']['x'] : false; - } - - /** - * Get info from message (error) - */ - function get_info_from_message_error($packet = NULL) - { - $error = preg_replace('#^\/$#', '', ($packet['message']['#']['error'][0]['@']['code'] . '/' . $packet['message']['#']['error'][0]['#'])); - return (is_array($packet)) ? $error : false; - } + // go on with authentication? + if (isset($this->features['stream:features'][0]['#']['bind'])) + { + return $this->response($this->features); + } + break; - // ====================================================================== - // <iq/> parsers - // ====================================================================== + case 'stream:features': + // Resource binding after successful authentication + if (isset($this->session['authenticated'])) + { + // session required? + $this->session['sess_required'] = isset($xml['stream:features'][0]['#']['session']); + + $this->send("<iq type='set' id='bind_1'> + <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> + <resource>functions_jabber.phpbb.php</resource> + </bind> + </iq>"); + return $this->response($this->listen()); + } - /** - * Get info from iq (from) - */ - function get_info_from_iq_from($packet = NULL) - { - return (is_array($packet)) ? $packet['iq']['@']['from'] : false; - } + // Let's use TLS if SSL is not enabled and we can actually use it + if (!$this->session['ssl'] && $this->can_use_tls() && isset($xml['stream:features'][0]['#']['starttls'])) + { + $this->add_to_log('Switching to TLS.'); + $this->send("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n"); + return $this->response($this->listen()); + } - /** - * Get info from iq (type) - */ - function get_info_from_iq_type($packet = NULL) - { - return (is_array($packet)) ? $packet['iq']['@']['type'] : false; - } + // Does the server support SASL authentication? + // I hope so, because we do (and no other method). + if (isset($xml['stream:features'][0]['#']['mechanisms'][0]['@']['xmlns']) && $xml['stream:features'][0]['#']['mechanisms'][0]['@']['xmlns'] == 'urn:ietf:params:xml:ns:xmpp-sasl') + { + // Now decide on method + $methods = array(); - /** - * Get info from iq (id) - */ - function get_info_from_iq_id($packet = NULL) - { - return (is_array($packet)) ? $packet['iq']['@']['id'] : false; - } + foreach ($xml['stream:features'][0]['#']['mechanisms'][0]['#']['mechanism'] as $value) + { + $methods[] = $value['#']; + } - /** - * Get info from iq (key) - */ - function get_info_from_iq_key($packet = NULL) - { - return (is_array($packet) && isset($packet['iq']['#']['query'][0]['#']['key'][0]['#'])) ? $packet['iq']['#']['query'][0]['#']['key'][0]['#'] : false; - } + // we prefer this one + if (in_array('DIGEST-MD5', $methods)) + { + $this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>"); + } + else if (in_array('PLAIN', $methods) && ($this->session['ssl'] || $this->session['tls'])) + { + // we don't want to use this (neither does the server usually) if no encryption is in place + $this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>" + . base64_encode(chr(0) . $this->username . '@' . $this->server . chr(0) . $this->password) . + '</auth>'); + } + else + { + // not good... + $this->add_to_log('Error: No authentication method supported.'); + $this->disconnect(); + return false; + } - /** - * Get info from iq (error) - */ - function get_info_from_iq_error($packet = NULL) - { - $error = preg_replace('#^\/$#', '', ($packet['iq']['#']['error'][0]['@']['code'] . '/' . $packet['iq']['#']['error'][0]['#'])); - return (is_array($packet)) ? $error : false; - } + return $this->response($this->listen()); + } + else + { + // ok, this is it. bye. + $this->add_to_log('Error: Server does not offer SASL authentication.'); + $this->disconnect(); + return false; + } + break; - // ====================================================================== - // <message/> handlers - // ====================================================================== + case 'challenge': + // continue with authentication...a challenge literally -_- + $decoded = base64_decode($xml['challenge'][0]['#']); + $decoded = $this->parse_data($decoded); - /** - * Message type normal - */ - function handler_message_normal($packet) - { - $from = $packet['message']['@']['from']; - $this->add_to_log("EVENT: Message (type normal) from $from"); - } + if (!isset($decoded['digest-uri'])) + { + $decoded['digest-uri'] = 'xmpp/'. $this->server; + } - /** - * Message type chat - */ - function handler_message_chat($packet) - { - $from = $packet['message']['@']['from']; - $this->add_to_log("EVENT: Message (type chat) from $from"); - } + // better generate a cnonce, maybe it's needed + $str = ''; + mt_srand((double)microtime()*10000000); - /** - * Message type groupchat - */ - function handler_message_groupchat($packet) - { - $from = $packet['message']['@']['from']; - $this->add_to_log("EVENT: Message (type groupchat) from $from"); - } + for ($i = 0; $i < 32; $i++) + { + $str .= chr(mt_rand(0, 255)); + } + $decoded['cnonce'] = base64_encode($str); - /** - * Message type headline - */ - function handler_message_headline($packet) - { - $from = $packet['message']['@']['from']; - $this->add_to_log("EVENT: Message (type headline) from $from"); - } + // second challenge? + if (isset($decoded['rspauth'])) + { + $this->send("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>"); + } + else + { + $response = array( + 'username' => $this->username, + 'response' => $this->encrypt_password(array_merge($decoded, array('nc' => '00000001'))), + 'charset' => 'utf-8', + 'nc' => '00000001', + ); + + foreach (array('nonce', 'qop', 'digest-uri', 'realm', 'cnonce') as $key) + { + if (isset($decoded[$key])) + { + $response[$key] = $decoded[$key]; + } + } - /** - * Message type error - */ - function handler_message_error($packet) - { - $from = $packet['message']['@']['from']; - $this->add_to_log("EVENT: Message (type error) from $from"); - } + $this->send("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" . base64_encode($this->implode_data($response)) . '</response>'); + } - // ====================================================================== - // <iq/> handlers - // ====================================================================== + return $this->response($this->listen()); + break; - /** - * application version updates - */ - function handler_iq_jabber_iq_autoupdate($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + case 'failure': + $this->add_to_log('Error: Server sent "failure".'); + $this->disconnect(); + return false; + break; - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:autoupdate from $from"); - } + case 'proceed': + // continue switching to TLS + $meta = stream_get_meta_data($this->connection); + socket_set_blocking($this->connection, 1); - /** - * interactive server component properties - */ - function handler_iq_jabber_iq_agent($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + if (!stream_socket_enable_crypto($this->connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) + { + $this->add_to_log('Error: TLS mode change failed.'); + return false; + } - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:agent from $from"); - } + socket_set_blocking($this->connection, $meta['blocked']); + $this->session['tls'] = true; - /** - * method to query interactive server components - */ - function handler_iq_jabber_iq_agents($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + // new stream + $this->send("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); + $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:agents from $from"); - } + return $this->response($this->listen()); + break; - /** - * simple client authentication - */ - function handler_iq_jabber_iq_auth($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + case 'success': + // Yay, authentication successful. + $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); + $this->session['authenticated'] = true; - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:auth from $from"); - } + // we have to wait for another response + return $this->response($this->listen()); + break; - /** - * out of band data - */ - function handler_iq_jabber_iq_oob($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + case 'iq': + // we are not interested in IQs we did not expect + if (!isset($xml['iq'][0]['@']['id'])) + { + return false; + } - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:oob from $from"); - } + // multiple possibilities here + switch ($xml['iq'][0]['@']['id']) + { + case 'bind_1': + $this->session['jid'] = $xml['iq'][0]['#']['bind'][0]['#']['jid'][0]['#']; + + // and (maybe) yet another request to be able to send messages *finally* + if ($this->session['sess_required']) + { + $this->send("<iq to='{$this->server}' type='set' id='sess_1'> + <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/> + </iq>"); + return $this->response($this->listen()); + } + + return true; + break; + + case 'sess_1': + return true; + break; + + case 'reg_1': + // more than instructions, username and password? + if (sizeof($xml['iq'][0]['#']['query'][0]['#']) > 3) + { + $this->add_to_log('Server requires too much data for registration.'); + return false; + } + + $this->send("<iq type='set' id='reg_2'> + <query xmlns='jabber:iq:register'> + <username>" . utf8_htmlspecialchars($this->username) . "</username> + <password>" . utf8_htmlspecialchars($this->password) . "</password> + </query> + </iq>"); + return $this->response($this->listen()); + break; + + case 'reg_2': + // registration end + if (isset($xml['iq'][0]['#']['error'])) + { + $this->add_to_log('Warning: Registration failed.'); + return false; + } + return true; + break; + + case 'unreg_1': + return true; + break; + + default: + $this->add_to_log('Notice: Received unexpected IQ.'); + return false; + break; + } + break; - /** - * method to store private data on the server - */ - function handler_iq_jabber_iq_private($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + case 'message': + // we are only interested in content... + if (!isset($xml['message'][0]['#']['body'])) + { + return false; + } - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:private from $from"); - } + $message['body'] = $xml['message'][0]['#']['body'][0]['#']; + $message['from'] = $xml['message'][0]['@']['from']; - /** - * method for interactive registration - */ - function handler_iq_jabber_iq_register($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + if (isset($xml['message'][0]['#']['subject'])) + { + $message['subject'] = $xml['message'][0]['#']['subject'][0]['#']; + } + $this->session['messages'][] = $message; + break; - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:register from $from"); + default: + // hm...don't know this response + $this->add_to_log('Notice: Unknown server response (' . key($xml) . ')'); + return false; + break; + } } - /** - * client roster management - */ - function handler_iq_jabber_iq_roster($packet) + function send_message($to, $text, $subject = '', $type = 'normal') { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); - - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:roster from $from"); - } + if (!isset($this->session['jid'])) + { + return false; + } - /** - * method for searching a user database - */ - function handler_iq_jabber_iq_search($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + if (!in_array($type, array('chat', 'normal', 'error', 'groupchat', 'headline'))) + { + $type = 'normal'; + } - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:search from $from"); + return $this->send("<message from='" . utf8_htmlspecialchars($this->session['jid']) . "' to='" . utf8_htmlspecialchars($to) . "' type='$type' id='" . uniqid('msg') . "'> + <subject>" . utf8_htmlspecialchars($subject) . "</subject> + <body>" . utf8_htmlspecialchars($text) . "</body> + </message>" + ); } /** - * method for requesting the current time + * Encrypts a password as in RFC 2831 + * @param array $data Needs data from the client-server connection + * @access public + * @return string */ - function handler_iq_jabber_iq_time($packet) + function encrypt_password($data) { - if ($this->keep_alive_id == $this->get_info_from_iq_id($packet)) + // let's me think about <challenge> again... + foreach (array('realm', 'cnonce', 'digest-uri') as $key) { - $this->returned_keep_alive = true; - $this->connected = true; - - $this->add_to_log('EVENT: Keep-Alive returned, connection alive.'); + if (!isset($data[$key])) + { + $data[$key] = ''; + } } - $type = $this->get_info_from_iq_type($packet); - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); - $id = ($id != '') ? $id : 'time_' . time(); + $pack = md5($this->username . ':' . $data['realm'] . ':' . $this->password); - if ($type == 'get') + if (isset($data['authzid'])) { - $payload = '<utc>' . gmdate("Ydm\TH:i:s") . '</utc><tz>' . date('T') . '</tz><display>' . date("Y/d/m h:i:s A") . '</display>'; - $this->send_iq($from, 'result', $id, 'jabber:iq:time', $payload); + $a1 = pack('H32', $pack) . sprintf(':%s:%s:%s', $data['nonce'], $data['cnonce'], $data['authzid']); + } + else + { + $a1 = pack('H32', $pack) . sprintf(':%s:%s', $data['nonce'], $data['cnonce']); } - $this->add_to_log("EVENT: jabber:iq:time (type $type) from $from"); - } + // should be: qop = auth + $a2 = 'AUTHENTICATE:'. $data['digest-uri']; - /** - */ - function handler_iq_error($packet) - { - // We'll do something with these later. This is a placeholder so that errors don't bounce back and forth. + return md5(sprintf('%s:%s:%s:%s:%s:%s', md5($a1), $data['nonce'], $data['nc'], $data['cnonce'], $data['qop'], md5($a2))); } /** - * method for requesting version + * parse_data like a="b",c="d",... + * @param string $data + * @access public + * @return array a => b ... */ - function handler_iq_jabber_iq_version($packet) + function parse_data($data) { - $type = $this->get_info_from_iq_type($packet); - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); - $id = ($id != '') ? $id : 'version_' . time(); + // super basic, but should suffice + $data = explode(',', $data); + $pairs = array(); - if ($type == 'get') + foreach ($data as $pair) { - $payload = "<name>{$this->iq_version_name}</name> - <os>{$this->iq_version_os}</os> - <version>{$this->iq_version_version}</version>"; - - //$this->SendIq($from, 'result', $id, "jabber:iq:version", $payload); + $dd = strpos($pair, '='); + if ($dd) + { + $pairs[substr($pair, 0, $dd)] = trim(substr($pair, $dd + 1), '"'); + } } - - $this->add_to_log("EVENT: jabber:iq:version (type $type) from $from -- DISABLED"); + return $pairs; } - // ====================================================================== - // Generic handlers - // ====================================================================== - /** - * Generic handler for unsupported requests + * opposite of jabber::parse_data() + * @param array $data + * @access public + * @return string */ - function handler_not_implemented($packet) + function implode_data($data) { - $packet_type = $this->_get_packet_type($packet); - $from = call_user_func(array(&$this, 'get_info_from_' . strtolower($packet_type) . '_from'), $packet); - $id = call_user_func(array(&$this, 'get_info_from_' . strtolower($packet_type) . '_id'), $packet); - - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: Unrecognized <$packet_type/> from $from"); + $return = array(); + foreach ($data as $key => $value) + { + $return[] = $key . '="' . $value . '"'; + } + return implode(',', $return); } - // ====================================================================== - // Third party code - // m@d pr0ps to the coders ;) - // ====================================================================== - /** * xmlize() * @author Hans Anderson @@ -1334,6 +724,12 @@ class jabber { $data = trim($data); + if (substr($data, 0, 5) != '<?xml') + { + // mod + $data = '<root>'. $data . '</root>'; + } + $vals = $index = $array = array(); $parser = xml_parser_create($encoding); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); @@ -1344,8 +740,13 @@ class jabber $i = 0; $tagname = $vals[$i]['tag']; - $array[$tagname]['@'] = (isset($vals[$i]['attributes'])) ? $vals[$i]['attributes'] : array(); - $array[$tagname]['#'] = $this->_xml_depth($vals, $i); + $array[$tagname][0]['@'] = (isset($vals[$i]['attributes'])) ? $vals[$i]['attributes'] : array(); + $array[$tagname][0]['#'] = $this->_xml_depth($vals, $i); + + if (substr($data, 0, 5) != '<?xml') + { + $array = $array['root'][0]['#']; + } return $array; } @@ -1407,106 +808,6 @@ class jabber return $children; } - - /** - * TraverseXMLize() - * @author acebone@f2s.com - * @copyright acebone@f2s.com, a HUGE help! - */ - function traverse_xmlize($array, $arr_name = 'array', $level = 0) - { - if ($level == 0) - { - echo '<pre>'; - } - - foreach ($array as $key => $val) - { - if (is_array($val)) - { - $this->traverse_xmlize($val, $arr_name . '[' . $key . ']', $level + 1); - } - else - { - $GLOBALS['traverse_array'][] = '$' . $arr_name . '[' . $key . '] = "' . $val . "\"\n"; - } - } - - if ($level == 0) - { - echo '</pre>'; - } - - return 1; - } -} - -/** -* Jabber Connector -* @package phpBB3 -*/ -class cjp_standard_connector -{ - var $active_socket; - - /** - * Open socket - */ - function open_socket($server, $port) - { - if (function_exists('dns_get_record')) - { - $record = dns_get_record("_xmpp-client._tcp.$server", DNS_SRV); - - if (!empty($record)) - { - $server = $record[0]['target']; - $port = $record[0]['port']; - } - } - - $errno = 0; - $errstr = ''; - - if ($this->active_socket = @fsockopen($server, $port, $errno, $errstr, 5)) - { - @socket_set_blocking($this->active_socket, 0); - @socket_set_timeout($this->active_socket, 31536000); - - return true; - } - else - { - return false; - } - } - - /** - * Close socket - */ - function close_socket() - { - return @fclose($this->active_socket); - } - - /** - * Write to socket - */ - function write_to_socket($data) - { - return @fwrite($this->active_socket, $data); - } - - /** - * Read from socket - */ - function read_from_socket($chunksize) - { - $buffer = @fread($this->active_socket, $chunksize); - $buffer = (STRIP) ? stripslashes($buffer) : $buffer; - - return $buffer; - } } ?>
\ No newline at end of file diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index d4052a8968..01d8b4854f 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -458,7 +458,7 @@ class messenger if (!$use_queue) { include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx); - $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], $config['jab_password'], $config['jab_resource']); + $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], $config['jab_password']); if (!$this->jabber->connect()) { @@ -466,19 +466,17 @@ class messenger return false; } - if (!$this->jabber->send_auth()) + if (!$this->jabber->login()) { $this->error('JABBER', 'Could not authorise on Jabber server<br />' . $this->jabber->get_log()); return false; } - $this->jabber->send_presence(NULL, NULL, 'online'); foreach ($addresses as $address) { - $this->jabber->send_message($address, 'normal', NULL, array('body' => $this->msg, 'subject' => $this->subject)); + $this->jabber->send_message($address, $this->msg, $this->subject); } - sleep(1); $this->jabber->disconnect(); } else @@ -592,7 +590,7 @@ class queue } include_once($phpbb_root_path . 'includes/functions_jabber.'.$phpEx); - $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], $config['jab_password'], $config['jab_resource']); + $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], $config['jab_password']); if (!$this->jabber->connect()) { @@ -600,12 +598,11 @@ class queue continue 2; } - if (!$this->jabber->send_auth()) + if (!$this->jabber->login()) { messenger::error('JABBER', 'Could not authorise on Jabber server'); continue 2; } - $this->jabber->send_presence(NULL, NULL, 'online'); break; @@ -647,7 +644,7 @@ class queue case 'jabber': foreach ($addresses as $address) { - if ($this->jabber->send_message($address, 'normal', NULL, array('body' => $msg, 'subject' => $subject)) === false) + if ($this->jabber->send_message($address, $msg, $subject) === false) { messenger::error('JABBER', $this->jabber->get_log()); continue 3; @@ -669,7 +666,6 @@ class queue case 'jabber': // Hang about a couple of secs to ensure the messages are // handled, then disconnect - sleep(1); $this->jabber->disconnect(); break; } diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index f771f71c22..f650eda9f4 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -1712,7 +1712,7 @@ class user extends session $img_data = &$imgs[$img]; - if (empty($img_data) || $width !== false) + if (empty($img_data)) { if (!isset($this->img_array[$img])) { @@ -1735,7 +1735,7 @@ class user extends session break; case 'width': - return $img_data['width']; + return ($width === false) ? $img_data['width'] : $width; break; case 'height': @@ -1743,7 +1743,9 @@ class user extends session break; default: - return '<img src="' . $img_data['src'] . '"' . (($img_data['width']) ? ' width="' . $img_data['width'] . '"' : '') . (($img_data['height']) ? ' height="' . $img_data['height'] . '"' : '') . ' alt="' . $alt . '" title="' . $alt . '" />'; + $use_width = ($width === false) ? $img_data['width'] : $width; + + return '<img src="' . $img_data['src'] . '"' . (($use_width) ? ' width="' . $use_width . '"' : '') . (($img_data['height']) ? ' height="' . $img_data['height'] . '"' : '') . ' alt="' . $alt . '" title="' . $alt . '" />'; break; } } diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 5ba0c9f50f..fc3523a4b8 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -592,7 +592,6 @@ if (version_compare($current_version, '3.0.RC1', '<=')) AND ug.user_id = u.user_id'; $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) { $bots[] = (int)$row['user_id']; @@ -612,6 +611,11 @@ if (version_compare($current_version, '3.0.RC1', '<=')) sql_column_change($map_dbms, POSTS_TABLE, 'post_subject', array('XSTEXT_UNI', '', 'true_sort')); } + $sql = 'DELETE FROM ' . CONFIG_TABLE . " WHERE config_name = 'jab_resource'"; + _sql($sql, $errored, $error_ary); + + set_config('jab_use_ssl', '0'); + $no_updates = false; } diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index 5e7d69b38e..a25703241b 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -113,7 +113,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('jab_host', ''); INSERT INTO phpbb_config (config_name, config_value) VALUES ('jab_password', ''); INSERT INTO phpbb_config (config_name, config_value) VALUES ('jab_package_size', '20'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('jab_port', '5222'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('jab_resource', ''); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('jab_use_ssl', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('jab_username', ''); INSERT INTO phpbb_config (config_name, config_value) VALUES ('ldap_base_dn', ''); INSERT INTO phpbb_config (config_name, config_value) VALUES ('ldap_email', ''); @@ -148,7 +148,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_login_attempts INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_name_chars', '20'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_pass_chars', '30'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_poll_options', '10'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_post_chars', '0'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_post_chars', '60000'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_post_font_size', '200'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_post_img_height', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_post_img_width', '0'); diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php index 77aa273251..d5c72e0e9c 100644 --- a/phpBB/language/en/acp/board.php +++ b/phpBB/language/en/acp/board.php @@ -412,32 +412,24 @@ $lang = array_merge($lang, array( // Jabber settings $lang = array_merge($lang, array( - 'ACP_JABBER_SETTINGS_EXPLAIN' => 'Here you can enable and control the use of Jabber for instant messaging and board notifications. Jabber is an open source protocol and therefore available for use by anyone. Some Jabber servers include gateways or transports which allow you to contact users on other networks. Not all servers offer all transports and changes in protocols can prevent transports from operating. Note that it may take several seconds to update Jabber account details, so do not stop the script until it is completed!', + 'ACP_JABBER_SETTINGS_EXPLAIN' => 'Here you can enable and control the use of Jabber for instant messaging and board notifications. Jabber is an open source protocol and therefore available for use by anyone. Some Jabber servers include gateways or transports which allow you to contact users on other networks. Not all servers offer all transports and changes in protocols can prevent transports from operating. Please be sure to enter already registered account details - phpBB will use the details you enter here as is.', 'ERR_JAB_AUTH' => 'Could not authorise on Jabber server.', 'ERR_JAB_CONNECT' => 'Could not connect to Jabber server.', - 'ERR_JAB_PASSCHG' => 'Could not change password.', - 'ERR_JAB_PASSFAIL' => 'Password update failed, %s.', - 'ERR_JAB_REGISTER' => 'An error occurred trying to register this account, %s.', - 'ERR_JAB_USERNAME' => 'The username specified already exists, please choose an alternative.', - - 'JAB_CHANGED' => 'Jabber account changed successfully.', 'JAB_ENABLE' => 'Enable Jabber', 'JAB_ENABLE_EXPLAIN' => 'Enables use of Jabber messaging and notifications.', 'JAB_PACKAGE_SIZE' => 'Jabber package size', - 'JAB_PACKAGE_SIZE_EXPLAIN' => 'This is the number of messages sent in one package. If set to 0 the message is sent immediately and is not queued for later sending.', + 'JAB_PACKAGE_SIZE_EXPLAIN' => 'This is the number of messages sent in one package. If set to 0 the message is sent immediately and will not be queued for later sending.', 'JAB_PASSWORD' => 'Jabber password', - 'JAB_PASS_CHANGED' => 'Jabber password changed successfully.', 'JAB_PORT' => 'Jabber port', 'JAB_PORT_EXPLAIN' => 'Leave blank unless you know it is not port 5222.', - 'JAB_REGISTERED' => 'New account registered successfully.', - 'JAB_RESOURCE' => 'Jabber resource', - 'JAB_RESOURCE_EXPLAIN' => 'The resource locates this particular connection, e.g. board, home, etc.', 'JAB_SERVER' => 'Jabber server', 'JAB_SERVER_EXPLAIN' => 'See %sjabber.org%s for a list of servers.', 'JAB_SETTINGS_CHANGED' => 'Jabber settings changed successfully.', + 'JAB_USE_SSL' => 'Use SSL to connect', + 'JAB_USE_SSL_EXPLAIN' => 'If enabled a secure connection is tried to be established. The Jabber port will be modified to 5223 if port 5222 is specified.', 'JAB_USERNAME' => 'Jabber username', - 'JAB_USERNAME_EXPLAIN' => 'If this user is not registered it will be created if possible.', + 'JAB_USERNAME_EXPLAIN' => 'Specify a registered username. The username will not be checked for validity.', )); ?>
\ No newline at end of file diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index e81d75325c..286552129b 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -291,7 +291,7 @@ $lang = array_merge($lang, array( 'LOGIN_ERROR_PASSWORD_CONVERT' => 'It was not possible to convert your password when updating this bulletin board’s software. Please %srequest a new password%s. If you continue to have problems please contact the %sBoard Administrator%s.', 'LOGIN_ERROR_USERNAME' => 'You have specified an incorrect username. Please check your username and try again. If you continue to have problems please contact the %sBoard Administrator%s.', 'LOGIN_FORUM' => 'To view or post in this forum you must enter its password.', - 'LOGIN_INFO' => 'In order to login you must be registered. Registering takes only a few seconds but gives you increased capabilities. The board administrator may also grant additional permissions to registered users. Before you login please ensure you are familiar with our terms of use and related policies. Please ensure you read any forum rules as you navigate around the board.', + 'LOGIN_INFO' => 'In order to login you must be registered. Registering takes only a few moments but gives you increased capabilities. The board administrator may also grant additional permissions to registered users. Before you register please ensure you are familiar with our terms of use and related policies. Please ensure you read any forum rules as you navigate around the board.', 'LOGIN_VIEWFORUM' => 'The board requires you to be registered and logged in to view this forum.', 'LOGIN_EXPLAIN_EDIT' => 'In order to edit posts in this forum you have to be registered and logged in.', 'LOGOUT' => 'Logout', diff --git a/phpBB/posting.php b/phpBB/posting.php index 599b7ddae7..17d426240b 100644 --- a/phpBB/posting.php +++ b/phpBB/posting.php @@ -844,7 +844,7 @@ if ($submit || $preview || $refresh) $sql = 'SELECT topic_type, forum_id FROM ' . TOPICS_TABLE . " WHERE topic_id = $topic_id"; - $result = $db->sql_query_limit($sql, 1); + $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -852,6 +852,21 @@ if ($submit || $preview || $refresh) { $to_forum_id = request_var('to_forum_id', 0); + if ($to_forum_id) + { + $sql = 'SELECT forum_type + FROM ' . FORUMS_TABLE . ' + WHERE forum_id = ' . $to_forum_id; + $result = $db->sql_query($sql); + $forum_type = (int) $db->sql_fetchfield('forum_type'); + $db->sql_freeresult($result); + + if ($forum_type != FORUM_POST || !$auth->acl_get('f_post', $to_forum_id)) + { + $to_forum_id = 0; + } + } + if (!$to_forum_id) { include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx); diff --git a/phpBB/styles/prosilver/template/forumlist_body.html b/phpBB/styles/prosilver/template/forumlist_body.html index 30c7e5ffee..7d267410aa 100644 --- a/phpBB/styles/prosilver/template/forumlist_body.html +++ b/phpBB/styles/prosilver/template/forumlist_body.html @@ -25,9 +25,9 @@ <!-- IF not forumrow.S_IS_CAT --> <li class="row"> - <dl class="icon" style="background-image: url({forumrow.FORUM_FOLDER_IMG_SRC});"> + <dl class="icon" style="background-image: url({forumrow.FORUM_FOLDER_IMG_SRC}); background-repeat: no-repeat;"> <dt> - <!-- IF forumrow.FORUM_IMAGE --><div style="float: left; padding-top: 5px; margin-right: 5px;">{forumrow.FORUM_IMAGE}</div><!-- ENDIF --> + <!-- IF forumrow.FORUM_IMAGE --><div class="forum-image">{forumrow.FORUM_IMAGE}</div><!-- ENDIF --> <a href="{forumrow.U_VIEWFORUM}" class="forumtitle">{forumrow.FORUM_NAME}</a><br /> {forumrow.FORUM_DESC} <!-- IF forumrow.MODERATORS --> diff --git a/phpBB/styles/prosilver/template/mcp_forum.html b/phpBB/styles/prosilver/template/mcp_forum.html index 17e57578ba..7c8d1a374f 100644 --- a/phpBB/styles/prosilver/template/mcp_forum.html +++ b/phpBB/styles/prosilver/template/mcp_forum.html @@ -34,8 +34,8 @@ <!-- BEGIN topicrow --> <li class="row<!-- IF topicrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ENDIF -->"> - <dl class="icon" style="background-image: url({topicrow.TOPIC_FOLDER_IMG_SRC});"> - <dt <!-- IF topicrow.TOPIC_ICON_IMG and S_TOPIC_ICONS -->style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG});"<!-- ENDIF -->> + <dl class="icon" style="background-image: url({topicrow.TOPIC_FOLDER_IMG_SRC}); background-repeat: no-repeat;"> + <dt <!-- IF topicrow.TOPIC_ICON_IMG and S_TOPIC_ICONS -->style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF -->> <!-- IF topicrow.S_SELECT_TOPIC --><a href="{topicrow.U_SELECT_TOPIC}" class="topictitle">[ {L_SELECT_MERGE} ]</a> <!-- ENDIF --> <a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a> <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF --> diff --git a/phpBB/styles/prosilver/template/memberlist_search.html b/phpBB/styles/prosilver/template/memberlist_search.html index ba7cf302ff..4f37fbda1b 100644 --- a/phpBB/styles/prosilver/template/memberlist_search.html +++ b/phpBB/styles/prosilver/template/memberlist_search.html @@ -11,7 +11,10 @@ function insert_marked(users) { if (typeof(users.length) == "undefined") { - insert_user(users.value); + if (users.checked) + { + insert_user(users.value); + } } else if (users.length > 0) { diff --git a/phpBB/styles/prosilver/template/posting_poll_body.html b/phpBB/styles/prosilver/template/posting_poll_body.html index ca721748e9..ba0014ce57 100644 --- a/phpBB/styles/prosilver/template/posting_poll_body.html +++ b/phpBB/styles/prosilver/template/posting_poll_body.html @@ -7,6 +7,12 @@ <fieldset class="fields2"> <!-- IF S_SHOW_POLL_BOX --> + <!-- IF S_POLL_DELETE --> + <dl> + <dt><label for="poll_delete">{L_POLL_DELETE}:</label></dt> + <dd><label for="poll_delete"><input type="checkbox" name="poll_delete" id="poll_delete"<!-- IF S_POLL_DELETE_CHECKED --> checked="checked"<!-- ENDIF --> /> </label></dd> + </dl> + <!-- ENDIF --> <dl> <dt><label for="poll_title">{L_POLL_QUESTION}:</label></dt> <dd><input type="text" name="poll_title" id="poll_title" maxlength="255" value="{POLL_TITLE}" class="inputbox" /></dd> @@ -38,10 +44,10 @@ </dl> <!-- ENDIF --> - <!-- ELSE --> + <!-- ELSEIF S_POLL_DELETE --> <dl class="fields1"> <dt><label for="poll_delete">{L_POLL_DELETE}:</label></dt> - <dd><label for="poll_delete"><input type="checkbox" name="poll_delete" id="poll_delete"<!-- IF S_POLL_DELETE_CHECKED --> checked="checked"<!-- ENDIF --> /> {L_DELETE_POST_WARN}</label></dd> + <dd><label for="poll_delete"><input type="checkbox" name="poll_delete" id="poll_delete"<!-- IF S_POLL_DELETE_CHECKED --> checked="checked"<!-- ENDIF --> /> </label></dd> </dl> <!-- ENDIF --> </fieldset> diff --git a/phpBB/styles/prosilver/template/search_results.html b/phpBB/styles/prosilver/template/search_results.html index adb955034f..104193bff2 100644 --- a/phpBB/styles/prosilver/template/search_results.html +++ b/phpBB/styles/prosilver/template/search_results.html @@ -52,8 +52,8 @@ <!-- BEGIN searchresults --> <li class="row<!-- IF searchresults.S_ROW_COUNT is even --> bg1<!-- ELSE --> bg2<!-- ENDIF -->"> - <dl class="icon" style="background-image: url({searchresults.TOPIC_FOLDER_IMG_SRC});"> - <dt <!-- IF searchresults.TOPIC_ICON_IMG -->style="background-image: url({T_ICONS_PATH}{searchresults.TOPIC_ICON_IMG});"<!-- ENDIF -->> + <dl class="icon" style="background-image: url({searchresults.TOPIC_FOLDER_IMG_SRC}); background-repeat: no-repeat;"> + <dt <!-- IF searchresults.TOPIC_ICON_IMG -->style="background-image: url({T_ICONS_PATH}{searchresults.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF -->> <!-- IF searchresults.S_UNREAD_TOPIC --><a href="{searchresults.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --> <a href="{searchresults.U_VIEW_TOPIC}" class="topictitle">{searchresults.TOPIC_TITLE}</a> {searchresults.ATTACH_ICON_IMG} <!-- IF searchresults.S_TOPIC_UNAPPROVED or searchresults.S_POSTS_UNAPPROVED --><a href="{searchresults.U_MCP_QUEUE}">{searchresults.UNAPPROVED_IMG}</a> <!-- ENDIF --> diff --git a/phpBB/styles/prosilver/template/ucp_main_bookmarks.html b/phpBB/styles/prosilver/template/ucp_main_bookmarks.html index 7d59df1a02..0011e48c92 100644 --- a/phpBB/styles/prosilver/template/ucp_main_bookmarks.html +++ b/phpBB/styles/prosilver/template/ucp_main_bookmarks.html @@ -31,8 +31,8 @@ <dd class="mark"><input type="checkbox" name="t[{topicrow.TOPIC_ID}]" id="t{topicrow.TOPIC_ID}" /></dd> </dl> <!-- ELSE --> - <dl class="icon" style="background-image: url({topicrow.TOPIC_FOLDER_IMG_SRC});"> - <dt style="<!-- IF topicrow.TOPIC_ICON_IMG -->background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG});<!-- ENDIF -->" title="{topicrow.TOPIC_FOLDER_IMG_ALT}"> + <dl class="icon" style="background-image: url({topicrow.TOPIC_FOLDER_IMG_SRC}); background-repeat: no-repeat;"> + <dt style="<!-- IF topicrow.TOPIC_ICON_IMG -->background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;<!-- ENDIF -->" title="{topicrow.TOPIC_FOLDER_IMG_ALT}"> <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a> <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF --> <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br /> diff --git a/phpBB/styles/prosilver/template/ucp_main_front.html b/phpBB/styles/prosilver/template/ucp_main_front.html index d49166fe62..bc6c4ef9b8 100644 --- a/phpBB/styles/prosilver/template/ucp_main_front.html +++ b/phpBB/styles/prosilver/template/ucp_main_front.html @@ -13,8 +13,8 @@ <ul class="topiclist cplist"> <!-- BEGIN topicrow --> <li class="row<!-- IF topicrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->"> - <dl class="icon" style="background-image: url({topicrow.TOPIC_FOLDER_IMG_SRC});"> - <dt <!-- IF topicrow.TOPIC_ICON_IMG -->style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG});"<!-- ENDIF -->> + <dl class="icon" style="background-image: url({topicrow.TOPIC_FOLDER_IMG_SRC}); background-repeat: no-repeat;"> + <dt <!-- IF topicrow.TOPIC_ICON_IMG -->style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF -->> <!-- IF topicrow.S_UNREAD --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a><br /> <!-- IF topicrow.PAGINATION --><strong class="pagination"><span>{topicrow.PAGINATION}</span></strong><!-- ENDIF --> <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} {L_POSTED_ON_DATE} {topicrow.FIRST_POST_TIME} diff --git a/phpBB/styles/prosilver/template/ucp_main_subscribed.html b/phpBB/styles/prosilver/template/ucp_main_subscribed.html index d806507e06..a6fae14507 100644 --- a/phpBB/styles/prosilver/template/ucp_main_subscribed.html +++ b/phpBB/styles/prosilver/template/ucp_main_subscribed.html @@ -21,7 +21,7 @@ <!-- BEGIN forumrow --> <li class="row<!-- IF forumrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->"> - <dl class="icon" style="background-image: url({forumrow.FORUM_FOLDER_IMG_SRC});"> + <dl class="icon" style="background-image: url({forumrow.FORUM_FOLDER_IMG_SRC}); background-repeat: no-repeat;"> <dt><a href="{forumrow.U_VIEWFORUM}" class="forumtitle">{forumrow.FORUM_NAME}</a><br /> <!-- IF forumrow.LAST_POST_TIME -->{L_LAST_POST} {L_POST_BY_AUTHOR} <!-- IF forumrow.U_LAST_POST_AUTHOR --><a href="{forumrow.U_LAST_POST_AUTHOR}">{forumrow.LAST_POST_AUTHOR}</a> <!-- ELSE -->{forumrow.LAST_POST_AUTHOR}<!-- ENDIF --> <a href="{forumrow.U_LAST_POST}">{LAST_POST_IMG}</a> {L_POSTED_ON_DATE} {forumrow.LAST_POST_TIME} @@ -49,8 +49,8 @@ <!-- BEGIN topicrow --> <li class="row<!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ELSEIF topicrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->"> - <dl class="icon" style="background-image: url({topicrow.TOPIC_FOLDER_IMG_SRC});"> - <dt style="<!-- IF topicrow.TOPIC_ICON_IMG -->background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG});<!-- ENDIF -->" title="{topicrow.TOPIC_FOLDER_IMG_ALT}"> + <dl class="icon" style="background-image: url({topicrow.TOPIC_FOLDER_IMG_SRC}); background-repeat: no-repeat;"> + <dt style="<!-- IF topicrow.TOPIC_ICON_IMG -->background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;<!-- ENDIF -->" title="{topicrow.TOPIC_FOLDER_IMG_ALT}"> <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a> <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF --> <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br /> diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html b/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html index 3704d8e84b..d3c37580fb 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html +++ b/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html @@ -57,8 +57,8 @@ <!-- BEGIN messagerow --> <li class="row<!-- IF messagerow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- IF messagerow.PM_CLASS --> {messagerow.PM_CLASS}<!-- ENDIF -->"> - <dl class="icon" style="background-image: url({messagerow.FOLDER_IMG_SRC});"> - <dt<!-- IF messagerow.PM_ICON_URL and S_PM_ICONS --> style="background-image: url({messagerow.PM_ICON_URL});"<!-- ENDIF -->> + <dl class="icon" style="background-image: url({messagerow.FOLDER_IMG_SRC}); background-repeat: no-repeat;"> + <dt<!-- IF messagerow.PM_ICON_URL and S_PM_ICONS --> style="background-image: url({messagerow.PM_ICON_URL}); background-repeat: no-repeat;"<!-- ENDIF -->> <!-- IF messagerow.S_PM_DELETED --> <a href="{messagerow.U_REMOVE_PM}" class="topictitle">{L_DELETE_MESSAGE}</a><br /> diff --git a/phpBB/styles/prosilver/template/ucp_register.html b/phpBB/styles/prosilver/template/ucp_register.html index 2bb8272337..5bb55c66f8 100644 --- a/phpBB/styles/prosilver/template/ucp_register.html +++ b/phpBB/styles/prosilver/template/ucp_register.html @@ -65,7 +65,7 @@ <dl> <dt><label for="{profile_fields.FIELD_ID}">{profile_fields.LANG_NAME}:<!-- IF profile_fields.S_REQUIRED --> *<!-- ENDIF --></label> <!-- IF profile_fields.LANG_EXPLAIN --><br /><span>{profile_fields.LANG_EXPLAIN}</span><!-- ENDIF --> - <!-- IF profile_fields.ERROR --><br /><span style="color:red">{profile_fields.ERROR}</span><!-- ENDIF --></dt> + <!-- IF profile_fields.ERROR --><br /><span class="error">{profile_fields.ERROR}</span><!-- ENDIF --></dt> <dd>{profile_fields.FIELD}</dd> </dl> <!-- END profile_fields --> diff --git a/phpBB/styles/prosilver/template/viewforum_body.html b/phpBB/styles/prosilver/template/viewforum_body.html index 1049617f66..97021d53d3 100644 --- a/phpBB/styles/prosilver/template/viewforum_body.html +++ b/phpBB/styles/prosilver/template/viewforum_body.html @@ -137,8 +137,8 @@ <!-- ENDIF --> <li class="row<!-- IF topicrow.S_ROW_COUNT is even --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- IF topicrow.S_POST_ANNOUNCE --> announce<!-- ENDIF --><!-- IF topicrow.S_POST_STICKY --> sticky<!-- ENDIF --><!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ENDIF -->"> - <dl class="icon" style="background-image: url({topicrow.TOPIC_FOLDER_IMG_SRC});"> - <dt style="<!-- IF topicrow.TOPIC_ICON_IMG and S_TOPIC_ICONS -->background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG});<!-- ENDIF -->" title="{topicrow.TOPIC_FOLDER_IMG_ALT}"><!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a> + <dl class="icon" style="background-image: url({topicrow.TOPIC_FOLDER_IMG_SRC}); background-repeat: no-repeat;"> + <dt style="<!-- IF topicrow.TOPIC_ICON_IMG and S_TOPIC_ICONS -->background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;<!-- ENDIF -->" title="{topicrow.TOPIC_FOLDER_IMG_ALT}"><!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a> <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF --> <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br /> <!-- IF topicrow.PAGINATION --><strong class="pagination"><span>{topicrow.PAGINATION}</span></strong><!-- ENDIF --> diff --git a/phpBB/styles/prosilver/theme/colours.css b/phpBB/styles/prosilver/theme/colours.css index 70d89e7370..017d9bcb51 100644 --- a/phpBB/styles/prosilver/theme/colours.css +++ b/phpBB/styles/prosilver/theme/colours.css @@ -875,6 +875,10 @@ label { color: #425067; } +option.disabled-option { + color: graytext; +} + /* Definition list layout for forms ---------------------------------------- */ dd label { @@ -954,4 +958,4 @@ a.button1:hover, input.button1:hover, a.button2:hover, input.button2:hover, inpu input.search { background-image: url("{T_THEME_PATH}/images/icon_textbox_search.gif"); -}
\ No newline at end of file +} diff --git a/phpBB/styles/prosilver/theme/content.css b/phpBB/styles/prosilver/theme/content.css index 9245127553..12a53e281c 100644 --- a/phpBB/styles/prosilver/theme/content.css +++ b/phpBB/styles/prosilver/theme/content.css @@ -56,6 +56,12 @@ ul.topiclist li.row dt a.subforum { padding: 0 0 0 12px; } +.forum-image { + float: left; + padding-top: 5px; + margin-right: 5px; +} + li.row { border-top: 1px solid #FFFFFF; border-bottom: 1px solid #8f8f8f; diff --git a/phpBB/styles/prosilver/theme/forms.css b/phpBB/styles/prosilver/theme/forms.css index 0ef5743698..272fd920ba 100644 --- a/phpBB/styles/prosilver/theme/forms.css +++ b/phpBB/styles/prosilver/theme/forms.css @@ -32,6 +32,10 @@ option { padding-right: 1em; } +option.disabled-option { + color: graytext; +} + textarea { font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; width: 60%; diff --git a/phpBB/styles/subsilver2/template/memberlist_search.html b/phpBB/styles/subsilver2/template/memberlist_search.html index c64d7321d0..253fff9ecf 100644 --- a/phpBB/styles/subsilver2/template/memberlist_search.html +++ b/phpBB/styles/subsilver2/template/memberlist_search.html @@ -12,7 +12,10 @@ { if (typeof(users.length) == "undefined") { - insert_user(users.value); + if (users.checked) + { + insert_user(users.value); + } } else if (users.length > 0) { diff --git a/phpBB/styles/subsilver2/theme/stylesheet.css b/phpBB/styles/subsilver2/theme/stylesheet.css index a2d8829f9a..f0223a2b6f 100644 --- a/phpBB/styles/subsilver2/theme/stylesheet.css +++ b/phpBB/styles/subsilver2/theme/stylesheet.css @@ -482,6 +482,10 @@ option { padding: 0 1em 0 0; } +option.disabled-option { + color: graytext; +} + .rtl option { padding: 0 0 0 1em; } |