Browse Source

Merge branch 'master' of https://github.com/Spuds/playpen

Conflicts:
	Sources/ManageAttachments.php
	Themes/default/languages/Admin.english.php
emanuele 13 years ago
parent
commit
940e9cb70b
52 changed files with 1031 additions and 681 deletions
  1. 2 2
      SSI.php
  2. 1 1
      Sources/Display.php
  3. 16 14
      Sources/Load.php
  4. 10 2
      Sources/ManageAttachments.php
  5. 1 0
      Sources/ManagePermissions.php
  6. 1 1
      Sources/MessageIndex.php
  7. 2 7
      Sources/Packages.php
  8. 473 273
      Sources/Post.php
  9. 1 0
      Sources/Profile-View.php
  10. 1 1
      Sources/QueryString.php
  11. 1 1
      Sources/Recent.php
  12. 1 1
      Sources/Search.php
  13. 6 5
      Sources/Subs-Editor.php
  14. 2 2
      Sources/Subs-Graphics.php
  15. 168 212
      Sources/Subs-Post.php
  16. 4 4
      Sources/Subs.php
  17. 28 0
      Themes/default/Errors.template.php
  18. 2 2
      Themes/default/GenericList.template.php
  19. 11 13
      Themes/default/GenericMenu.template.php
  20. 1 1
      Themes/default/ManageBoards.template.php
  21. 1 1
      Themes/default/ManageLanguages.template.php
  22. 6 6
      Themes/default/ManageMembergroups.template.php
  23. 31 23
      Themes/default/ManageNews.template.php
  24. 1 1
      Themes/default/ManagePaid.template.php
  25. 6 7
      Themes/default/ManagePermissions.template.php
  26. 1 1
      Themes/default/Memberlist.template.php
  27. 4 4
      Themes/default/MessageIndex.template.php
  28. 49 14
      Themes/default/Packages.template.php
  29. 41 9
      Themes/default/PersonalMessage.template.php
  30. 30 7
      Themes/default/Post.template.php
  31. 8 8
      Themes/default/Recent.template.php
  32. 2 2
      Themes/default/Who.template.php
  33. 0 1
      Themes/default/css/admin.css
  34. 26 7
      Themes/default/css/index.css
  35. BIN
      Themes/default/images/helptopics.png
  36. BIN
      Themes/default/images/post/poll.png
  37. BIN
      Themes/default/images/selected_open.png
  38. BIN
      Themes/default/images/sort_down.png
  39. BIN
      Themes/default/images/sort_up.png
  40. 2 0
      Themes/default/languages/Admin.english.php
  41. 2 10
      Themes/default/languages/Errors.english.php
  42. 1 0
      Themes/default/languages/ManagePermissions.english.php
  43. 1 1
      Themes/default/languages/ManageSmileys.english.php
  44. 37 1
      Themes/default/languages/Post.english.php
  45. 1 1
      Themes/default/languages/Search.english.php
  46. 2 2
      Themes/default/languages/index.english.php
  47. 15 4
      Themes/default/scripts/topic.js
  48. 2 2
      other/install.php
  49. 10 9
      other/install_2-1_mysql.sql
  50. 9 8
      other/install_2-1_postgresql.sql
  51. 9 8
      other/install_2-1_sqlite.sql
  52. 2 2
      other/upgrade.php

+ 2 - 2
SSI.php

@@ -431,7 +431,7 @@ function ssi_recentTopics($num_recent = 8, $exclude_boards = null, $include_boar
 		$include_boards = array();
 	}
 
-	$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless');
+	$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'poll', 'moved', 'recycled', 'wireless');
 	$icon_sources = array();
 	foreach ($stable_icons as $icon)
 		$icon_sources[$icon] = 'images_url';
@@ -1629,7 +1629,7 @@ function ssi_boardNews($board = null, $limit = null, $start = null, $length = nu
 	$smcFunc['db_free_result']($request);
 
 	// Load the message icons - the usual suspects.
-	$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless');
+	$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'poll', 'moved', 'recycled', 'wireless');
 	$icon_sources = array();
 	foreach ($stable_icons as $icon)
 		$icon_sources[$icon] = 'images_url';

+ 1 - 1
Sources/Display.php

@@ -1096,7 +1096,7 @@ function prepareDisplayContext($reset = false)
 	// $context['icon_sources'] says where each icon should come from - here we set up the ones which will always exist!
 	if (empty($context['icon_sources']))
 	{
-		$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless', 'clip');
+		$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'poll', 'moved', 'recycled', 'wireless', 'clip');
 		$context['icon_sources'] = array();
 		foreach ($stable_icons as $icon)
 			$context['icon_sources'][$icon] = 'images_url';

+ 16 - 14
Sources/Load.php

@@ -2598,16 +2598,17 @@ function cache_quick_get($key, $file, $function, $params, $level = 1)
 
 /**
  * Puts value in the cache under key for ttl seconds.
- * It may "miss" so shouldn't be depended on, and may go to any of many various caching servers.
- * It supports:
  *
- * Turck MMCache: http://turck-mmcache.sourceforge.net/index_old.html#api
- * Xcache: http://xcache.lighttpd.net/wiki/XcacheApi
- * memcache: http://www.php.net/memcache
- * APC: http://www.php.net/apc
- * eAccelerator: http://bart.eaccelerator.net/doc/phpdoc/
- * Zend: http://files.zend.com/help/Zend-Platform/output_cache_functions.htm
- * Zend: http://files.zend.com/help/Zend-Platform/zend_cache_functions.htm
+ * - It may "miss" so shouldn't be depended on 
+ * - Uses the cahce engine chosen in the ACP and saved in settings.php
+ * - It supports:
+ *     Turck MMCache: http://turck-mmcache.sourceforge.net/index_old.html#api
+ *     Xcache: http://xcache.lighttpd.net/wiki/XcacheApi
+ *     memcache: http://www.php.net/memcache
+ *     APC: http://www.php.net/apc
+ *     eAccelerator: http://bart.eaccelerator.net/doc/phpdoc/
+ *     Zend: http://files.zend.com/help/Zend-Platform/output_cache_functions.htm
+ *     Zend: http://files.zend.com/help/Zend-Platform/zend_cache_functions.htm
  *
  * @param string $key
  * @param mixed $value
@@ -2729,8 +2730,8 @@ function cache_put_data($key, $value, $ttl = 120)
 
 /**
  * Gets the value from the cache specified by key, so long as it is not older than ttl seconds.
- * It may often "miss", so shouldn't be depended on.
- * It supports the same as cache_put_data().
+ * - It may often "miss", so shouldn't be depended on.
+ * - It supports the same as cache_put_data().
  *
  * @param string $key
  * @param int $ttl = 120
@@ -2823,9 +2824,10 @@ function cache_get_data($key, $ttl = 120)
 
 /**
  * Get memcache servers.
- * This function is used by cache_get_data() and cache_put_data().
- * It attempts to connect to a random server in the cache_memcached setting.
- * It recursively calls itself up to $level times.
+ *
+ * - This function is used by cache_get_data() and cache_put_data().
+ * - It attempts to connect to a random server in the cache_memcached setting.
+ * - It recursively calls itself up to $level times.
  *
  * @param int $level = 3
  */

+ 10 - 2
Sources/ManageAttachments.php

@@ -93,6 +93,12 @@ function ManageAttachmentSettings($return_config = false)
 	// Perform a test to see if the GD module is installed.
 	$testGD = get_extension_funcs('gd');
 	$txt['attachmentUploadDir_multiple_configure'] = '<a href="' . $scripturl . '?action=admin;area=manageattachments;sa=attachpaths">[' . $txt['attachmentUploadDir_multiple_configure'] . ']</a>';
+	
+	// See if we can find if the server is set up to support the attacment limits
+	$post_max_size = ini_get('post_max_size');
+	$upload_max_filesize = ini_get('upload_max_filesize');
+	$testPM = !empty($post_max_size) ? (memoryReturnBytes($post_max_size) >= (isset($modSettings['attachmentPostLimit']) ? $modSettings['attachmentPostLimit'] * 1024 : 0)) : true;
+	$testUM = !empty($upload_max_filesize) ? (memoryReturnBytes($upload_max_filesize) >= (isset($modSettings['attachmentSizeLimit']) ? $modSettings['attachmentSizeLimit'] * 1024 : 0)) : true;
 
 	$config_vars = array(
 		array('title', 'attachment_manager_settings'),
@@ -106,10 +112,12 @@ function ManageAttachmentSettings($return_config = false)
 			empty($modSettings['currentAttachmentUploadDir']) ? array('text', 'attachmentUploadDir', 'subtext' => $txt['attachmentUploadDir_multiple_configure'], 40, 'invalid' => !$context['valid_upload_dir']) : array('var_message', 'attachmentUploadDir_multiple', 'message' => 'attachmentUploadDir_multiple_configure'),
 			array('text', 'attachmentDirSizeLimit', 'subtext' => $txt['zero_for_no_limit'], 6, 'postinput' => $txt['kilobyte']),
 			array('text', 'attachmentPostLimit', 'subtext' => $txt['zero_for_no_limit'], 6, 'postinput' => $txt['kilobyte']),
+			array('warning', empty($testPM) ? 'attachment_postsize_warning' : ''),
 			array('text', 'attachmentSizeLimit', 'subtext' => $txt['zero_for_no_limit'], 6, 'postinput' => $txt['kilobyte']),
+			array('warning', empty($testUM) ? 'attachment_filesize_warning' : ''),
 			array('text', 'attachmentNumPerPostLimit', 'subtext' => $txt['zero_for_no_limit'], 6),
 			// Security Items
-		'',
+		array('title', 'attachment_security_settings'),
 			// Extension checks etc.
 			array('check', 'attachmentCheckExtensions'),
 			array('text', 'attachmentExtensions', 40),
@@ -120,8 +128,8 @@ function ManageAttachmentSettings($return_config = false)
 		'',
 			array('warning', 'attachment_image_paranoid_warning'),
 			array('check', 'attachment_image_paranoid'),
-		'',
 			// Thumbnail settings.
+		array('title', 'attachment_thumbnail_settings'),
 			array('check', 'attachmentShowImages'),
 			array('check', 'attachmentThumbnails'),
 			array('check', 'attachment_thumb_png'),

+ 1 - 0
Sources/ManagePermissions.php

@@ -1404,6 +1404,7 @@ function loadAllPermissions($loadType = 'classic')
 		'membergroup' => array(
 			'simple' => array(
 				'view_basic_info',
+				'disable_censor',
 				'use_pm_system',
 				'post_calendar',
 				'edit_profile',

+ 1 - 1
Sources/MessageIndex.php

@@ -312,7 +312,7 @@ function MessageIndex()
 		$fake_ascending = false;
 
 	// Setup the default topic icons...
-	$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless', 'clip');
+	$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'poll', 'moved', 'recycled', 'wireless', 'clip');
 	$context['icon_sources'] = array();
 	foreach ($stable_icons as $icon)
 		$context['icon_sources'][$icon] = 'images_url';

+ 2 - 7
Sources/Packages.php

@@ -1442,13 +1442,8 @@ function PackageBrowse()
 			'additional_rows' => array(
 				array(
 					'position' => 'bottom_of_list',
-					'value' => (
-					$context['sub_action'] == 'browse' ? '
-			<div class="padding smalltext floatleft">
-				' . $txt['package_installed_key'] . '
-				<img src="' . $settings['images_url'] . '/icons/package_installed.png" alt="" class="centericon" style="margin-left: 1ex;" /> ' . $txt['package_installed_current'] . '
-				<img src="' . $settings['images_url'] . '/icons/package_old.png" alt="" class="centericon" style="margin-left: 2ex;" /> ' . $txt['package_installed_old'] . '
-			</div>' : '<a class="button_link" href="' . $scripturl . '?action=admin;area=packages;sa=flush;' . $context['session_var'] . '=' . $context['session_id'] . '" onclick="return confirm(\'' . $txt['package_delete_list_warning'] . '\');">' . $txt['delete_list'] . '</a><span style="float: right; margin:.5em;"></span><a class="button_link" href="#" onclick="document.getElementById(\'advanced_box\').style.display = document.getElementById(\'advanced_box\').style.display == \'\' ? \'none\' : \'\'; return false;">' .  $txt['package_advanced_button'] . '</a>'), 
+					'value' => ($context['sub_action'] == 'browse' ? '<div class="padding smalltext">' . $txt['package_installed_key'] . '<img src="' . $settings['images_url'] . '/icons/package_installed.png" alt="" class="centericon" style="margin-left: 1ex;" /> ' . $txt['package_installed_current'] . '<img src="' . $settings['images_url'] . '/icons/package_old.png" alt="" class="centericon" style="margin-left: 2ex;" /> ' . $txt['package_installed_old'] . '</div>' :
+					'<a class="button_link" href="' . $scripturl . '?action=admin;area=packages;sa=flush;' . $context['session_var'] . '=' . $context['session_id'] . '" onclick="return confirm(\'' . $txt['package_delete_list_warning'] . '\');">' . $txt['delete_list'] . '</a><span style="float: right; margin:.5em;"></span><a class="button_link" href="#" onclick="document.getElementById(\'advanced_box\').style.display = document.getElementById(\'advanced_box\').style.display == \'\' ? \'none\' : \'\'; return false;">' . $txt['package_advanced_button'] . '</a>'),
 				),
 			),
 		);

+ 473 - 273
Sources/Post.php

@@ -19,12 +19,12 @@ if (!defined('SMF'))
 
 /**
  * handles showing the post screen, loading the post to be modified, and loading any post quoted.
- * additionally handles previews of posts.
- * @uses the Post template and language file, main sub template.
- * allows wireless access using the protocol_post sub template.
- * requires different permissions depending on the actions, but most notably post_new, post_reply_own, and post_reply_any.
- * shows options for the editing and posting of calendar events and attachments, as well as the posting of polls.
- * accessed from ?action=post.
+ * - additionally handles previews of posts.
+ * - @uses the Post template and language file, main sub template.
+ * - allows wireless access using the protocol_post sub template.
+ * - requires different permissions depending on the actions, but most notably post_new, post_reply_own, and post_reply_any.
+ * - shows options for the editing and posting of calendar events and attachments, as well as the posting of polls.
+ * - accessed from ?action=post.
  */
 function Post()
 {
@@ -48,6 +48,18 @@ function Post()
 
 	require_once($sourcedir . '/Subs-Post.php');
 
+	// Any files to include for post?
+	if (!isset($post_includes) && !empty($modSettings['integrate_post_include']))
+	{
+		$post_includes = explode(',', $modSettings['integrate_post_include']);
+		foreach ($post_includes as $include)
+		{
+			$include = strtr(trim($include), array('$boarddir' => $boarddir, '$sourcedir' => $sourcedir, '$themedir' => $settings['theme_dir']));
+			if (file_exists($include))
+				require_once($include);
+		}
+	}
+
 	if (isset($_REQUEST['xml']))
 	{
 		$context['sub_template'] = 'post';
@@ -625,6 +637,7 @@ function Post()
 						continue;
 					$context['current_attachments'][] = array(
 						'name' => htmlspecialchars($row['filename']),
+						'size' => $row['filesize'],
 						'id' => $row['id_attach'],
 						'approved' => $row['approved'],
 					);
@@ -734,6 +747,7 @@ function Post()
 			if ($attachment['filesize'] >= 0 && !empty($modSettings['attachmentEnable']))
 				$context['current_attachments'][] = array(
 					'name' => htmlspecialchars($attachment['filename']),
+					'size' => $attachment['filesize'],
 					'id' => $attachment['id_attach'],
 					'approved' => $attachment['attachment_approved'],
 				);
@@ -840,14 +854,13 @@ function Post()
 		}
 	}
 
-	/**
-	 * This won't work if you're posting an event.
-	 */
-	if (allowedTo('post_attachment') || allowedTo('post_unapproved_attachments'))
+	$context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments')));
+	if ($context['can_post_attachment'])
 	{
-		if (empty($_SESSION['temp_attachments']))
-			$_SESSION['temp_attachments'] = array();
-
+		// If there are attachments, calculate the total size and how many.
+		$context['attachments']['total_size'] = 0;
+		$context['attachments']['quantity'] = 0;
+		if (!empty($context['current_attachments']))
 		if (!empty($modSettings['currentAttachmentUploadDir']))
 		{
 			if (!is_array($modSettings['attachmentUploadDir']))
@@ -862,151 +875,144 @@ function Post()
 		// If this isn't a new post, check the current attachments.
 		if (isset($_REQUEST['msg']))
 		{
-			$request = $smcFunc['db_query']('', '
-				SELECT COUNT(*), SUM(size)
-				FROM {db_prefix}attachments
-				WHERE id_msg = {int:id_msg}
-					AND attachment_type = {int:attachment_type}',
-				array(
-					'id_msg' => (int) $_REQUEST['msg'],
-					'attachment_type' => 0,
-				)
-			);
-			list ($quantity, $total_size) = $smcFunc['db_fetch_row']($request);
-			$smcFunc['db_free_result']($request);
-		}
-		else
-		{
-			$quantity = 0;
-			$total_size = 0;
+			$context['attachments']['quantity'] = count($context['current_attachments']);
+			foreach ($context['current_attachments'] as $attachment)
+				$context['attachments']['total_size'] += $attachment['size'];
 		}
 
-		$temp_start = 0;
+		// A bit of house keeping first.
+		if (!empty($_SESSION['temp_attachments']) && count($_SESSION['temp_attachments']) == 1)
+			unset($_SESSION['temp_attachments']);
 
 		if (!empty($_SESSION['temp_attachments']))
 		{
-			if ($context['current_action'] != 'post2' || !empty($_POST['from_qr']))
+			// Is this a request to delete them?
+			if (isset($_GET['delete_temp']))
 			{
-				$context['post_error']['messages'][] = $txt['error_temp_attachments'];
-				$context['error_type'] = 'minor';
+				foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
+				{
+					if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false)
+						if (file_exists($attachment['tmp_name']))
+							unlink($attachment['tmp_name']);
+				}
+				$context['post_error']['messages'][] = $txt['error_temp_attachments_gone'];
+				$_SESSION['temp_attachments'] = array();
 			}
-
-			foreach ($_SESSION['temp_attachments'] as $attachID => $name)
+			// Hmm, coming in fresh and there are files in session.
+			elseif ($context['current_action'] != 'post2' || !empty($_POST['from_qr']))
 			{
-				$temp_start++;
-
-				if (preg_match('~^post_tmp_' . $user_info['id'] . '_\d+$~', $attachID) == 0)
+				// Let's be nice and see if they belong here first.
+				if ((empty($_REQUEST['msg']) && empty($_SESSION['temp_attachments']['post']['msg']) && $_SESSION['temp_attachments']['post']['board'] == $board) || (!empty($_REQUEST['msg']) && $_SESSION['temp_attachments']['post']['msg'] == $_REQUEST['msg']))
 				{
-					unset($_SESSION['temp_attachments'][$attachID]);
-					continue;
-				}
+					// See if any files still exist before showing the warning message and the files attached.
+					foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
+					{
+						if (strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
+							continue;
 
-				if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del']))
-				{
-					$deleted_attachments = true;
-					unset($_SESSION['temp_attachments'][$attachID]);
-					@unlink($current_attach_dir . '/' . $attachID);
-					continue;
+						if (file_exists($attachment['tmp_name']))
+						{
+							$context['post_error']['messages'][] = $txt['error_temp_attachments_new'];
+							$context['files_in_session_warning'] = $txt['attached_files_in_session'];
+							unset($_SESSION['temp_attachments']['post']['files']);
+							break;
+						}
+					}
 				}
+				else
+				{
+					// Since, they don't belong here. Let's inform the user that they exist..
+					if (!empty($topic))
+						$delete_link = '<a href="' . $scripturl . '?action=post' .(!empty($_REQUEST['msg']) ? (';msg=' . $_REQUEST['msg']) : '') . (!empty($_REQUEST['last_msg']) ? (';last_msg=' . $_REQUEST['last_msg']) : '') . ';topic=' . $topic . ';delete_temp">' . $txt['here'] . '</a>';
+					else
+						$delete_link = '<a href="' . $scripturl . '?action=post;board=' . $board . ';delete_temp">' . $txt['here'] . '</a>';
+
+					// Compile a list of the files to show the user.
+					$file_list = array();
+					foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
+						if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false)
+							$file_list[] =  $attachment['name'];
+
+					$_SESSION['temp_attachments']['post']['files'] = $file_list;
+					$file_list = '<div class="attachments">' . implode('<br />', $file_list) . '</div>';
+
+					if (!empty($_SESSION['temp_attachments']['post']['msg']))
+					{
+						// We have a message id, so we can link back to the old topic they were trying to edit..
+						$goback_link = '<a href="' . $scripturl . '?action=post' .(!empty($_SESSION['temp_attachments']['post']['msg']) ? (';msg=' . $_SESSION['temp_attachments']['post']['msg']) : '') . (!empty($_SESSION['temp_attachments']['post']['last_msg']) ? (';last_msg=' . $_SESSION['temp_attachments']['post']['last_msg']) : '') . ';topic=' . $_SESSION['temp_attachments']['post']['topic'] . ';additionalOptions">' . $txt['here'] . '</a>';
 
-				$quantity++;
-				$total_size += filesize($current_attach_dir . '/' . $attachID);
-
-				$context['current_attachments'][] = array(
-					'name' => htmlspecialchars($name),
-					'id' => $attachID,
-					'approved' => 1,
-				);
+						$context['post_error']['messages'][] = vsprintf($txt['error_temp_attachments_found'], array($delete_link, $goback_link, $file_list));
+						$context['ignore_temp_attachments'] = true;
+					}
+					else
+					{
+						$context['post_error']['messages'][] = vsprintf($txt['error_temp_attachments_lost'], array($delete_link, $file_list));
+						$context['ignore_temp_attachments'] = true;
+					}
+				}
 			}
-		}
 
-		if (!empty($_POST['attach_del']))
-		{
-			$del_temp = array();
-			foreach ($_POST['attach_del'] as $i => $dummy)
-				$del_temp[$i] = (int) $dummy;
+			if (!empty($context['we_are_history']))
+				$context['post_error']['messages'][] = '<br />' . $context['we_are_history'];
 
-			foreach ($context['current_attachments'] as $k => $dummy)
-				if (!in_array($dummy['id'], $del_temp))
-				{
-					$context['current_attachments'][$k]['unchecked'] = true;
-					$deleted_attachments = !isset($deleted_attachments) || is_bool($deleted_attachments) ? 1 : $deleted_attachments + 1;
-					$quantity--;
-				}
-		}
-
-		if (!empty($_FILES['attachment']))
-			foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy)
+			foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
 			{
-				if ($_FILES['attachment']['name'][$n] == '')
-					continue;
-
-				if (!is_uploaded_file($_FILES['attachment']['tmp_name'][$n]) || (ini_get('open_basedir') == '' && !file_exists($_FILES['attachment']['tmp_name'][$n])))
-					fatal_lang_error('attach_timeout', 'critical');
+				if (isset($context['ignore_temp_attachments']) || isset($_SESSION['temp_attachments']['post']['files']))
+					break;
 
-				if (!empty($modSettings['attachmentSizeLimit']) && $_FILES['attachment']['size'][$n] > $modSettings['attachmentSizeLimit'] * 1024)
-					fatal_lang_error('file_too_big', false, array($modSettings['attachmentSizeLimit']));
-
-				$quantity++;
-				if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit'])
-					fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit']));
-
-				$total_size += $_FILES['attachment']['size'][$n];
-				if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024)
-					fatal_lang_error('file_too_big', false, array($modSettings['attachmentPostLimit']));
+				if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
+					continue;
 
-				if (!empty($modSettings['attachmentCheckExtensions']))
+				if ($attachID == 'initial_error')
 				{
-					if (!in_array(strtolower(substr(strrchr($_FILES['attachment']['name'][$n], '.'), 1)), explode(',', strtolower($modSettings['attachmentExtensions']))))
-						fatal_error($_FILES['attachment']['name'][$n] . '.<br />' . $txt['cant_upload_type'] . ' ' . $modSettings['attachmentExtensions'] . '.', false);
+					$context['post_error']['messages'][] = '<br />' . $txt['attach_no_upload'] . '<div style="padding: 0 1em;">' . (is_array($attachment) ? vsprintf($txt[$attachment[0]], $attachment[1]) : $txt[$attachment]) . '</div>';
+					unset($_SESSION['temp_attachments']);
+					break;
 				}
 
-				if (!empty($modSettings['attachmentDirSizeLimit']))
+				// Show any errors which might of occured.
+				if (!empty($attachment['errors']))
 				{
-					// Make sure the directory isn't full.
-					$dirSize = 0;
-					$dir = @opendir($current_attach_dir) or fatal_lang_error('cant_access_upload_path', 'critical');
-					while ($file = readdir($dir))
-					{
-						if ($file == '.' || $file == '..')
-							continue;
-
-						if (preg_match('~^post_tmp_\d+_\d+$~', $file) != 0)
-						{
-							// Temp file is more than 5 hours old!
-							if (filemtime($current_attach_dir . '/' . $file) < time() - 18000)
-								@unlink($current_attach_dir . '/' . $file);
-							continue;
-						}
-
-						$dirSize += filesize($current_attach_dir . '/' . $file);
-					}
-					closedir($dir);
+					$errors = empty($errors) ? '<br />' : '';
+					$errors .= vsprintf($txt['attach_warning'], $attachment['name']) . '<div style="padding: 0 1em;">';
+					foreach($attachment['errors'] as $error)
+						$errors .= (is_array($error) ? vsprintf($txt[$error[0]], $error[1]) : $txt[$error]) . '<br  />';
+					$errors .= '</div>';
+					$context['post_error']['messages'][] = $errors;
+
+					// Take out the trash.
+					unset($_SESSION['temp_attachments'][$attachID]);
+					if (file_exists($attachment['tmp_name']))
+						unlink($attachment['tmp_name']);
+					continue;
+				}
 
-					// Too big!  Maybe you could zip it or something...
-					if ($_FILES['attachment']['size'][$n] + $dirSize > $modSettings['attachmentDirSizeLimit'] * 1024)
-						fatal_lang_error('ran_out_of_space');
+				// More house keeping.
+				if (!file_exists($attachment['tmp_name']))
+				{
+					unset($_SESSION['temp_attachments'][$attachID]);
+					continue;
 				}
 
-				if (!is_writable($current_attach_dir))
-					fatal_lang_error('attachments_no_write', 'critical');
+				$context['attachments']['quantity']++;
+				$context['attachments']['total_size'] += $attachment['size'];
+				if (!isset($context['files_in_session_warning']))
+					$context['files_in_session_warning'] = $txt['attached_files_in_session'];
 
-				$attachID = 'post_tmp_' . $user_info['id'] . '_' . $temp_start++;
-				$_SESSION['temp_attachments'][$attachID] = basename($_FILES['attachment']['name'][$n]);
 				$context['current_attachments'][] = array(
-					'name' => htmlspecialchars(basename($_FILES['attachment']['name'][$n])),
+					'name' => '<u>' . htmlspecialchars($attachment['name']) . '</u>',
+					'size' => $attachment['size'],
 					'id' => $attachID,
+					'unchecked' => false,
 					'approved' => 1,
 				);
-
-				$destName = $current_attach_dir . '/' . $attachID;
-
-				if (!move_uploaded_file($_FILES['attachment']['tmp_name'][$n], $destName))
-					fatal_lang_error('attach_timeout', 'critical');
-				@chmod($destName, 0644);
 			}
+		}
 	}
 
+	if (!empty($context['post_error']['messages']) && (isset($newRepliesError) || isset($oldTopicError)))
+		$context['post_error']['messages'][] = '<br />';
+
 	// If we are coming here to make a reply, and someone has already replied... make a special warning message.
 	if (isset($newRepliesError))
 	{
@@ -1051,12 +1057,6 @@ function Post()
 	if (WIRELESS)
 		$context['linktree'][count($context['linktree']) - 1]['url'] = $scripturl . '?action=post;' . (!empty($topic) ? 'topic=' . $topic : 'board=' . $board) . '.' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . (int) $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] : '');
 
-	// If they've unchecked an attachment, they may still want to attach that many more files, but don't allow more than num_allowed_attachments.
-	// @todo This won't work if you're posting an event.
-	$context['num_allowed_attachments'] = empty($modSettings['attachmentNumPerPostLimit']) ? 50 : min($modSettings['attachmentNumPerPostLimit'] - count($context['current_attachments']) + (isset($deleted_attachments) ? $deleted_attachments : 0), $modSettings['attachmentNumPerPostLimit']);
-	$context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments'))) && $context['num_allowed_attachments'] > 0;
-	$context['can_post_attachment_unapproved'] = allowedTo('post_attachment');
-
 	$context['subject'] = addcslashes($form_subject, '"');
 	$context['message'] = str_replace(array('"', '<', '>', '&nbsp;'), array('&quot;', '&lt;', '&gt;', ' '), $form_message);
 
@@ -1089,6 +1089,20 @@ function Post()
 
 	if (!empty($context['icons']))
 		$context['icons'][count($context['icons']) - 1]['is_last'] = true;
+	
+	// Are we starting a poll? if set the poll icon as selected if its available
+	if (isset($_REQUEST['poll']))
+	{
+	    foreach ($context['icons'] as $icons)
+		{  
+			if (isset($icons['value']) && $icons['value'] == 'poll')
+			{
+				// if found we are done
+				$context['icon'] = 'poll';
+				break;
+			}
+		}
+	}
 
 	$context['icon_url'] = '';
 	for ($i = 0, $n = count($context['icons']); $i < $n; $i++)
@@ -1115,16 +1129,26 @@ function Post()
 	// If the user can post attachments prepare the warning labels.
 	if ($context['can_post_attachment'])
 	{
-		$context['allowed_extensions'] = strtr($modSettings['attachmentExtensions'], array(',' => ', '));
+		// If they've unchecked an attachment, they may still want to attach that many more files, but don't allow more than num_allowed_attachments.
+		$context['num_allowed_attachments'] = empty($modSettings['attachmentNumPerPostLimit']) ? 50 : min($modSettings['attachmentNumPerPostLimit'] - count($context['current_attachments']), $modSettings['attachmentNumPerPostLimit']);
+		$context['can_post_attachment_unapproved'] = allowedTo('post_attachment');
 		$context['attachment_restrictions'] = array();
+		$context['allowed_extensions'] = strtr(strtolower($modSettings['attachmentExtensions']), array(',' => ', '));
 		$attachmentRestrictionTypes = array('attachmentNumPerPostLimit', 'attachmentPostLimit', 'attachmentSizeLimit');
 		foreach ($attachmentRestrictionTypes as $type)
 			if (!empty($modSettings[$type]))
-				$context['attachment_restrictions'][] = sprintf($txt['attach_restrict_' . $type], $modSettings[$type]);
+			{
+				$context['attachment_restrictions'][] = sprintf($txt['attach_restrict_' . $type], comma_format($modSettings[$type], 0));
+				// Show some numbers. If they exist.
+				if ($type == 'attachmentNumPerPostLimit' && $context['attachments']['quantity'] > 0)
+					$context['attachment_restrictions'][] = sprintf($txt['attach_remaining'], $modSettings['attachmentNumPerPostLimit'] - $context['attachments']['quantity']);
+				elseif ($type == 'attachmentPostLimit' && $context['attachments']['total_size'] > 0)
+					$context['attachment_restrictions'][] = sprintf($txt['attach_available'], comma_format(round(max($modSettings['attachmentPostLimit'] - ($context['attachments']['total_size'] / 1028), 0)), 0));
+			}
 	}
 
 	$context['back_to_topic'] = isset($_REQUEST['goback']) || (isset($_REQUEST['msg']) && !isset($_REQUEST['subject']));
-	$context['show_additional_options'] = !empty($_POST['additional_options']) || !empty($_SESSION['temp_attachments']) || !empty($deleted_attachments);
+	$context['show_additional_options'] = !empty($_POST['additional_options']) || isset($_SESSION['temp_attachments']['post']) || isset($_GET['additionalOptions']);
 
 	$context['is_new_topic'] = empty($topic);
 	$context['is_new_post'] = !isset($_REQUEST['msg']);
@@ -1176,13 +1200,30 @@ function Post2()
 
 	// Sneaking off, are we?
 	if (empty($_POST) && empty($topic))
-		redirectexit('action=post;board=' . $board . '.0');
+	{
+		if (empty($_SERVER['CONTENT_LENGTH']))
+			redirectexit('action=post;board=' . $board . '.0');
+		else
+			fatal_lang_error('post_upload_error', false);
+	}
 	elseif (empty($_POST) && !empty($topic))
 		redirectexit('action=post;topic=' . $topic . '.0');
 
 	// No need!
 	$context['robot_no_index'] = true;
 
+	// Any files to include for post?
+	if (!empty($modSettings['integrate_post_include']))
+	{
+		$post_includes = explode(',', $modSettings['integrate_post_include']);
+		foreach ($post_includes as $include)
+		{
+			$include = strtr(trim($include), array('$boarddir' => $boarddir, '$sourcedir' => $sourcedir, '$themedir' => $settings['theme_dir']));
+			if (file_exists($include))
+				require_once($include);
+		}
+	}
+
 	// If we came from WYSIWYG then turn it back into BBC regardless.
 	if (!empty($_REQUEST['message_mode']) && isset($_REQUEST['message']))
 	{
@@ -1226,6 +1267,227 @@ function Post2()
 	require_once($sourcedir . '/Subs-Post.php');
 	loadLanguage('Post');
 
+	// First check to see if they are trying to delete any current attachments.
+	if (isset($_POST['attach_del']))
+	{
+		$keep_temp = array();
+		$keep_ids = array();
+		foreach ($_POST['attach_del'] as $dummy)
+			if (strpos($dummy, 'post_tmp_' . $user_info['id']) !== false)
+				$keep_temp[] = $dummy;
+			else
+				$keep_ids[] = (int) $dummy;
+
+		if (isset($_SESSION['temp_attachments']))
+			foreach($_SESSION['temp_attachments'] as $attachID => $attachment)
+			{
+				if ((isset($_SESSION['temp_attachments']['post']['files'], $attachment['name']) && in_array($attachment['name'], $_SESSION['temp_attachments']['post']['files'])) || in_array($attachID, $keep_temp) || strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
+					continue;
+
+				unset($_SESSION['temp_attachments'][$attachID]);
+				unlink($attachment['tmp_name']);
+			}
+
+		if (!empty($_REQUEST['msg']))
+		{
+			require_once($sourcedir . '/ManageAttachments.php');
+			$attachmentQuery = array(
+				'attachment_type' => 0,
+				'id_msg' => (int) $_REQUEST['msg'],
+				'not_id_attach' => $keep_ids,
+			);
+			removeAttachments($attachmentQuery);
+		}
+	}
+
+	// Then try to upload any attachments.
+	$context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments')));
+	if ($context['can_post_attachment'] && !empty($_FILES['attachment']) && empty($_POST['from_qr']))
+	{
+		// Make sure we're uploading to the right place.
+		if (!empty($modSettings['currentAttachmentUploadDir']))
+		{
+			if (!is_array($modSettings['attachmentUploadDir']))
+				$modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
+			// The current directory, of course!
+			$context['attach_dir'] = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']];
+		}
+		else
+			$context['attach_dir'] = $modSettings['attachmentUploadDir'];
+
+		// Is the attachments folder actualy there?
+		if (!is_dir($context['attach_dir']))
+		{
+			$initial_error = 'attach_folder_warning';
+			log_error(sprintf($txt['attach_folder_admin_warning'], $context['attach_dir']), 'critical');
+		}
+
+		// Check that the attachments folder is writable. No sense in proceeding if it isn't.
+		if (empty($initial_error) && !is_writable($context['attach_dir']))
+		{
+			// But, let's try to make it writable first.
+			chmod($context['attach_dir'], 0755);
+			if (!is_writable($context['attach_dir']))
+			{
+				chmod($context['attach_dir'], 0775);
+				if (!is_writable($context['attach_dir']))
+				{
+					chmod($context['attach_dir'], 0777);
+					if (!is_writable($context['attach_dir']))
+						$initial_error = 'attachments_no_write';
+				}
+			}
+		}
+
+		if (!isset($initial_error) && !isset($context['attachments']))
+		{
+			// If this isn't a new post, check the current attachments.
+			if (isset($_REQUEST['msg']))
+			{
+				$request = $smcFunc['db_query']('', '
+					SELECT COUNT(*), SUM(size)
+					FROM {db_prefix}attachments
+					WHERE id_msg = {int:id_msg}
+						AND attachment_type = {int:attachment_type}',
+					array(
+						'id_msg' => (int) $_REQUEST['msg'],
+						'attachment_type' => 0,
+					)
+				);
+				list ($context['attachments']['quantity'], $context['attachments']['total_size']) = $smcFunc['db_fetch_row']($request);
+				$smcFunc['db_free_result']($request);
+			}
+			else
+				$context['attachments'] = array(
+					'quantity' => 0,
+					'total_size' => 0,
+				);
+		}
+
+		// Hmm. There are still files in session.
+		$ignore_temp = false;
+		if (!empty($_SESSION['temp_attachments']['post']['files']) && count($_SESSION['temp_attachments']) > 1)
+		{
+			// Let's try to keep them. But...
+			$ignore_temp = true;
+			// If new files are being added. We can't ignore those
+			foreach ($_FILES['attachment']['tmp_name'] as $dummy)
+				if (!empty($dummy))
+				{
+					$ignore_temp = false;
+					break;
+				}
+
+			// Need to make space for the new files. So, bye bye.
+			if (!$ignore_temp)
+			{
+				foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
+					if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false)
+						unlink($attachment['tmp_name']);
+
+				$context['we_are_history'] = $txt['error_temp_attachments_flushed'];
+				$_SESSION['temp_attachments'] = array();
+			}
+		}
+
+		if (!isset($_FILES['attachment']['name']))
+			$_FILES['attachment']['tmp_name'] = array();
+
+		if (!isset($_SESSION['temp_attachments']))
+			$_SESSION['temp_attachments'] = array();
+
+		// Remember where we are at. If it's anywhere at all.
+		if (!$ignore_temp)
+			$_SESSION['temp_attachments']['post'] = array(
+				'msg' => !empty($_REQUEST['msg']) ? $_REQUEST['msg'] : 0,
+				'last_msg' => !empty($_REQUEST['last_msg']) ? $_REQUEST['last_msg'] : 0,
+				'topic' => !empty($topic) ? $topic : 0,
+				'board' => !empty($board) ? $board : 0,
+			);
+
+		// If we have an itital error, lets just display it.
+		if (!empty($initial_error))
+		{
+			$_SESSION['temp_attachments']['initial_error'] = $initial_error;
+
+			// And delete the files 'cos they ain't going nowhere.
+			foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy)
+				if (file_exists($_FILES['attachment']['tmp_name'][$n]))
+					unlink($_FILES['attachment']['tmp_name'][$n]);
+
+			$_FILES['attachment']['tmp_name'] = array();
+		}
+
+		// Loop through $_FILES['attachment'] array and move each file to the current attachments folder.
+		foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy)
+		{
+			if ($_FILES['attachment']['name'][$n] == '')
+				continue;
+
+			// First, let's first check for PHP upload errors.
+			$errors = array();
+			if (!empty($_FILES['attachment']['error'][$n]))
+			{
+				if ($_FILES['attachment']['error'][$n] == 2)
+					$errors[] = array('file_too_big', array($modSettings['attachmentSizeLimit']));
+				elseif ($_FILES['attachment']['error'][$n] == 6)
+					log_error($_FILES['attachment']['name'][$n] . ': ' . $txt['php_upload_error_6'], 'critical');
+				else
+					log_error($_FILES['attachment']['name'][$n] . ': ' . $txt['php_upload_error_' . $_FILES['attachment']['error'][$n]]);
+				if (empty($errors))
+					$errors[] = 'attach_php_error';
+			}
+
+			// Try to move and rename the file before doing any more checks on it.
+			$attachID = 'post_tmp_' . $user_info['id'] . '_' . md5(mt_rand());
+			$destName = $context['attach_dir'] . '/' . $attachID;
+			if (empty($errors))
+			{
+				$_SESSION['temp_attachments'][$attachID] = array(
+					'name' => htmlspecialchars(basename($_FILES['attachment']['name'][$n])),
+					'tmp_name' => $destName,
+					'size' => $_FILES['attachment']['size'][$n],
+					'type' => $_FILES['attachment']['type'][$n],
+					'errors' => array(),
+				);
+
+				// Move the file to the attachments folder with a temp name for now.
+				if (@move_uploaded_file($_FILES['attachment']['tmp_name'][$n], $destName))
+					@chmod($destName, 0644);
+				else
+				{
+					$_SESSION['temp_attachments'][$attachID]['errors'][] = 'attach_timeout';
+					if (file_exists($_FILES['attachment']['tmp_name'][$n]))
+						unlink($_FILES['attachment']['tmp_name'][$n]);
+				}
+			}
+			else
+			{
+				$_SESSION['temp_attachments'][$attachID] = array(
+					'name' => htmlspecialchars(basename($_FILES['attachment']['name'][$n])),
+					'tmp_name' => $destName,
+					'errors' => $errors,
+				);
+
+				if (file_exists($_FILES['attachment']['tmp_name'][$n]))
+					unlink($_FILES['attachment']['tmp_name'][$n]);
+			}
+			// If there's no errors to this pont. We still do need to apply some addtional checks before we are finished.
+			if (empty($_SESSION['temp_attachments'][$attachID]['errors']))
+				attachmentChecks($attachID);
+		}
+	}
+	// Mod authors, finally a hook to hang an alternate attachment upload system upon
+	// Upload to the current attachment folder with the file name $attachID or 'post_tmp_' . $user_info['id'] . '_' . md5(mt_rand())
+	// Populate $_SESSION['temp_attachments'][$attachID] with the following:
+	//   name => The file name
+	//   tmp_name => Path to the temp file ($context['attach_dir'] . '/' . $attachID).
+	//   size => File size (required).
+	//   type => MIME type (optional if not available on upload).
+	//   errors => An array of errors (use the index of the $txt variable for that error).
+	// Template changes can be done using "integrate_upload_template".
+	call_integration_hook('integrate_attachment_upload', array());
+
 	// If this isn't a new topic load the topic info that we need.
 	if (!empty($topic))
 	{
@@ -1622,167 +1884,77 @@ function Post2()
 		$_POST['options'] = htmlspecialchars__recursive($_POST['options']);
 	}
 
-	// Check if they are trying to delete any current attachments....
-	if (isset($_REQUEST['msg'], $_POST['attach_del']) && (allowedTo('post_attachment') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments'))))
-	{
-		// @todo check attach_del; this will be executed when:
-		// modify a post with attachments; try to remove one, but receive an error
-		// (i.e. body empty); then check back the attachment
-
-		$del_temp = array();
-		foreach ($_POST['attach_del'] as $i => $dummy)
-			$del_temp[$i] = (int) $dummy;
-
-		require_once($sourcedir . '/ManageAttachments.php');
-		$attachmentQuery = array(
-			'attachment_type' => 0,
-			'id_msg' => (int) $_REQUEST['msg'],
-			'not_id_attach' => $del_temp,
-		);
-		removeAttachments($attachmentQuery);
-	}
 
 	// ...or attach a new file...
-	if (isset($_FILES['attachment']['name']) || (!empty($_SESSION['temp_attachments']) && empty($_POST['from_qr'])))
+	if (empty($ignore_temp) && $context['can_post_attachment'] && !empty($_SESSION['temp_attachments']) && empty($_POST['from_qr']))
 	{
-		// Verify they can post them!
-		if (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_attachments'))
-			isAllowedTo('post_attachment');
-
-		// Make sure we're uploading to the right place.
-		if (!empty($modSettings['currentAttachmentUploadDir']))
-		{
-			if (!is_array($modSettings['attachmentUploadDir']))
-				$modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
-
-			// The current directory, of course!
-			$current_attach_dir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']];
-		}
-		else
-			$current_attach_dir = $modSettings['attachmentUploadDir'];
-
-		// If this isn't a new post, check the current attachments.
-		if (isset($_REQUEST['msg']))
-		{
-			$request = $smcFunc['db_query']('', '
-				SELECT COUNT(*), SUM(size)
-				FROM {db_prefix}attachments
-				WHERE id_msg = {int:id_msg}
-					AND attachment_type = {int:attachment_type}',
-				array(
-					'id_msg' => (int) $_REQUEST['msg'],
-					'attachment_type' => 0,
-				)
-			);
-			list ($quantity, $total_size) = $smcFunc['db_fetch_row']($request);
-			$smcFunc['db_free_result']($request);
-		}
-		else
-		{
-			$quantity = 0;
-			$total_size = 0;
-		}
-
-		if (!empty($_SESSION['temp_attachments']))
-			foreach ($_SESSION['temp_attachments'] as $attachID => $name)
-			{
-				if (preg_match('~^post_tmp_' . $user_info['id'] . '_\d+$~', $attachID) == 0)
-					continue;
-
-				if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del']))
-				{
-					unset($_SESSION['temp_attachments'][$attachID]);
-					@unlink($current_attach_dir . '/' . $attachID);
-					continue;
-				}
-
-				$_FILES['attachment']['tmp_name'][] = $attachID;
-				$_FILES['attachment']['name'][] = $name;
-				$_FILES['attachment']['size'][] = filesize($current_attach_dir . '/' . $attachID);
-				list ($_FILES['attachment']['width'][], $_FILES['attachment']['height'][]) = @getimagesize($current_attach_dir . '/' . $attachID);
-
-				unset($_SESSION['temp_attachments'][$attachID]);
-			}
-
-		if (!isset($_FILES['attachment']['name']))
-			$_FILES['attachment']['tmp_name'] = array();
-
 		$attachIDs = array();
-		foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy)
+		$attach_errors = array();
+		if (!empty($context['we_are_history']))
+			$attach_errors[] = '<dd>' . $txt['error_temp_attachments_flushed'] . '<br /><br /></dd>';
+
+		foreach ($_SESSION['temp_attachments'] as  $attachID => $attachment)
 		{
-			if ($_FILES['attachment']['name'][$n] == '')
+			if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
 				continue;
 
-			// Have we reached the maximum number of files we are allowed?
-			$quantity++;
-			if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit'])
+			// If there was an initial error just show that message.
+			if ($attachID == 'initial_error')
 			{
-				checkSubmitOnce('free');
-				fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit']));
-			}
+				$attach_errors[] = '<dt>' . $txt['attach_no_upload'] . '</dt>';
+				$attach_errors[] = '<dd>' . (is_array($attachment) ? vsprintf($txt[$attachment[0]], $attachment[1]) : $txt[$attachment]) . '</dd>';
 
-			// Check the total upload size for this post...
-			$total_size += $_FILES['attachment']['size'][$n];
-			if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024)
-			{
-				checkSubmitOnce('free');
-				fatal_lang_error('file_too_big', false, array($modSettings['attachmentPostLimit']));
+				unset($_SESSION['temp_attachments']);
+				break;
 			}
 
 			$attachmentOptions = array(
 				'post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0,
 				'poster' => $user_info['id'],
-				'name' => $_FILES['attachment']['name'][$n],
-				'tmp_name' => $_FILES['attachment']['tmp_name'][$n],
-				'size' => $_FILES['attachment']['size'][$n],
+				'name' => $attachment['name'],
+				'tmp_name' => $attachment['tmp_name'],
+				'size' => isset($attachment['size']) ? $attachment['size'] : 0,
+				'mime_type' => isset($attachment['type']) ? $attachment['type'] : '',
 				'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment'),
+				'errors' => $attachment['errors'],
 			);
 
-			if (createAttachment($attachmentOptions))
+			if (empty($attachment['errors']))
 			{
-				$attachIDs[] = $attachmentOptions['id'];
-				if (!empty($attachmentOptions['thumb']))
-					$attachIDs[] = $attachmentOptions['thumb'];
-			}
-			else
-			{
-				if (in_array('could_not_upload', $attachmentOptions['errors']))
+				if (createAttachment($attachmentOptions))
 				{
-					checkSubmitOnce('free');
-					fatal_lang_error('attach_timeout', 'critical');
+					$attachIDs[] = $attachmentOptions['id'];
+					if (!empty($attachmentOptions['thumb']))
+						$attachIDs[] = $attachmentOptions['thumb'];
 				}
-				if (in_array('too_large', $attachmentOptions['errors']))
-				{
-					checkSubmitOnce('free');
-					fatal_lang_error('file_too_big', false, array($modSettings['attachmentSizeLimit']));
-				}
-				if (in_array('bad_extension', $attachmentOptions['errors']))
-				{
-					checkSubmitOnce('free');
-					fatal_error($attachmentOptions['name'] . '.<br />' . $txt['cant_upload_type'] . ' ' . $modSettings['attachmentExtensions'] . '.', false);
-				}
-				if (in_array('directory_full', $attachmentOptions['errors']))
-				{
-					checkSubmitOnce('free');
-					fatal_lang_error('ran_out_of_space', 'critical');
-				}
-				if (in_array('bad_filename', $attachmentOptions['errors']))
-				{
-					checkSubmitOnce('free');
-					fatal_error(basename($attachmentOptions['name']) . '.<br />' . $txt['restricted_filename'] . '.', 'critical');
-				}
-				if (in_array('taken_filename', $attachmentOptions['errors']))
-				{
-					checkSubmitOnce('free');
-					fatal_lang_error('filename_exists');
-				}
-				if (in_array('bad_attachment', $attachmentOptions['errors']))
+			}
+
+			if (!empty($attachmentOptions['errors']))
+			{
+				if (isset($br))
+					$attach_errors[] = '<dt>&nbsp;</dt>';
+				else
+					$br = '';
+
+				// Sort out the errors for display and delete any associated files.
+				$attach_errors[] = '<dt>' . vsprintf($txt['attach_warning'], $attachment['name']) . '</dt>';
+				$log_these = array('attachments_no_write', 'attach_timeout', 'ran_out_of_space', 'cant_access_upload_path', 'attach_0_byte_file');
+				foreach ($attachmentOptions['errors'] as $error)
 				{
-					checkSubmitOnce('free');
-					fatal_lang_error('bad_attachment');
+					if (!is_array($error))
+					{
+						$attach_errors[] = '<dd>' . $txt[$error] . '</dd>';
+						if (in_array($error, $log_these))
+							log_error($attachment['name'] . ': ' . $txt[$error], 'critical');
+					}
+					else
+						$attach_errors[] = '<dd>' . vsprintf($txt[$error[0]], $error[1]) . '</dd>';
 				}
+				if (file_exists($attachment['tmp_name']))
+					unlink($attachment['tmp_name']);
 			}
 		}
+		unset($_SESSION['temp_attachments']);
 	}
 
 	// Make the poll...
@@ -2058,6 +2230,35 @@ function Post2()
 	if (!empty($_POST['move']) && allowedTo('move_any'))
 		redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
 
+	// If there are attachment errors. Let's show a list to the user.
+	if (!empty($attach_errors))
+	{
+		global $settings, $scripturl;
+
+		loadTemplate('Errors');
+		$context['sub_template'] = 'attachment_errors';
+		$context['page_title'] = $txt['error_occured'];
+
+		$context['error_message'] = '<dl>';
+		$context['error_message'] .= implode("\n", $attach_errors);
+		$context['error_message'] .= '</dl>';
+
+		$context['linktree'][] = array(
+			'url' => $scripturl . '?topic=' . $topic . '.0',
+			'name' => $_POST['subject'],
+			'extra_before' => $settings['linktree_inline'] ? $txt['topic'] . ': ' : ''
+		);
+
+		if (isset($_REQUEST['msg']))
+			$context['redirect_link'] = '?topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'];
+		else
+			$context['redirect_link'] = '?topic=' . $topic . '.new#new';
+
+		$context['back_link'] = '?action=post;msg=' . $msgOptions['id'] . ';topic=' . $topic . ';additionalOptions#postAttachment';
+
+		obExit(null, true);
+	}
+
 	// Return to post if the mod is on.
 	if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback']))
 		redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], isBrowser('ie'));
@@ -2068,7 +2269,6 @@ function Post2()
 		redirectexit('board=' . $board . '.0');
 }
 
-// General function for topic announcements.
 /**
  * handle the announce topic function (action=announce).
  * checks the topic announcement permissions and loads the announcement template.

+ 1 - 0
Sources/Profile-View.php

@@ -2129,6 +2129,7 @@ function viewWarning($memID)
 	);
 
 	// Create the list for viewing.
+	require_once($sourcedir . '/Subs-List.php');
 	createList($listOptions);
 
 	// Create some common text bits for the template.

+ 1 - 1
Sources/QueryString.php

@@ -551,7 +551,7 @@ function cleanXml($string)
 	global $context;
 
 	// http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char
-	return preg_replace('~[\x00-\x08\x0B\x0C\x0E-\x19' . ($context['utf8'] ? '\x{D800}-\x{DFFF}\x{FFFE}\x{FFFF}' : '') . ']~' . ($context['utf8'] ? 'u' : ''), '', $string);
+	return preg_replace('~[\x00-\x08\x0B\x0C\x0E-\x19' . ($context['utf8'] ? '\x{FFFE}\x{FFFF}' : '') . ']~' . ($context['utf8'] ? 'u' : ''), '', $string);
 }
 
 /**

+ 1 - 1
Sources/Recent.php

@@ -653,7 +653,7 @@ function UnreadTopics()
 	}
 
 	// Setup the default topic icons... for checking they exist and the like ;)
-	$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless', 'clip');
+	$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'poll', 'moved', 'recycled', 'wireless', 'clip');
 	$context['icon_sources'] = array();
 	foreach ($stable_icons as $icon)
 		$context['icon_sources'][$icon] = 'images_url';

+ 1 - 1
Sources/Search.php

@@ -1803,7 +1803,7 @@ function PlushSearch2()
 	$context['key_words'] = &$searchArray;
 
 	// Setup the default topic icons... for checking they exist and the like!
-	$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless', 'clip');
+	$stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'poll', 'moved', 'recycled', 'wireless', 'clip');
 	$context['icon_sources'] = array();
 	foreach ($stable_icons as $icon)
 		$context['icon_sources'][$icon] = 'images_url';

+ 6 - 5
Sources/Subs-Editor.php

@@ -930,10 +930,10 @@ function fetchTagAttributes($text)
 
 /**
  * Retrieves a list of message icons.
- * Based on the settings, the array will either contain a list of default
- * message icons or a list of custom message icons retrieved from the database.
- * The board_id is needed for the custom message icons (which can be set for
- * each board individually).
+ * - Based on the settings, the array will either contain a list of default
+ *   message icons or a list of custom message icons retrieved from the database.
+ * - The board_id is needed for the custom message icons (which can be set for
+ *   each board individually).
  * 
  * @param int $board_id
  * @return array
@@ -958,7 +958,8 @@ function getMessageIcons($board_id)
 			array('value' => 'cheesy', 'name' => $txt['icon_cheesy']),
 			array('value' => 'grin', 'name' => $txt['icon_grin']),
 			array('value' => 'sad', 'name' => $txt['icon_sad']),
-			array('value' => 'wink', 'name' => $txt['icon_wink'])
+			array('value' => 'wink', 'name' => $txt['icon_wink']),
+			array('value' => 'poll', 'name' => $txt['icon_poll']),
 		);
 
 		foreach ($icons as $k => $dummy)

+ 2 - 2
Sources/Subs-Graphics.php

@@ -282,7 +282,7 @@ function imageMemoryCheck($sizes)
 	// doing the old 'set it and hope' way?
 	if (empty($modSettings['attachment_thumb_memory']))
 	{
-		setMemoryLimit('90M');
+		setMemoryLimit('128M');
 		return true;
 	}
 
@@ -358,7 +358,7 @@ function resizeImageFile($source, $destination, $max_width, $max_height, $prefer
 	else
 		$sizes = array(-1, -1, -1);
 		
-	// See if we have -or- can get the need memory for this operation
+	// See if we have -or- can get the needed memory for this operation
 	if (!imageMemoryCheck($sizes))
 		return false;
 

+ 168 - 212
Sources/Subs-Post.php

@@ -2042,49 +2042,23 @@ function createPost(&$msgOptions, &$topicOptions, &$posterOptions)
 
 /**
  * Create an attachment, with the given array of parameters.
+ * - Adds any addtional or missing parameters to $attachmentOptions.
+ * - Renames the temporary file.
+ * - Creates a thumbnail if the file is an image and the option enabled.
  *
  * @param array $attachmentOptions
  */
 function createAttachment(&$attachmentOptions)
 {
 	global $modSettings, $sourcedir, $smcFunc, $context;
+	global $txt, $boarddir;
 
 	require_once($sourcedir . '/Subs-Graphics.php');
 
-	// We need to know where this thing is going.
 	if (!empty($modSettings['currentAttachmentUploadDir']))
-	{
-		if (!is_array($modSettings['attachmentUploadDir']))
-			$modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
-
-		// Just use the current path for temp files.
-		$attach_dir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']];
 		$id_folder = $modSettings['currentAttachmentUploadDir'];
-	}
 	else
-	{
-		$attach_dir = $modSettings['attachmentUploadDir'];
 		$id_folder = 1;
-	}
-
-	$attachmentOptions['errors'] = array();
-	if (!isset($attachmentOptions['post']))
-		$attachmentOptions['post'] = 0;
-	if (!isset($attachmentOptions['approved']))
-		$attachmentOptions['approved'] = 1;
-
-	$already_uploaded = preg_match('~^post_tmp_' . $attachmentOptions['poster'] . '_\d+$~', $attachmentOptions['tmp_name']) != 0;
-	$file_restricted = ini_get('open_basedir') != '' && !$already_uploaded;
-
-	if ($already_uploaded)
-		$attachmentOptions['tmp_name'] = $attach_dir . '/' . $attachmentOptions['tmp_name'];
-
-	// Make sure the file actually exists... sometimes it doesn't.
-	if ((!$file_restricted && !file_exists($attachmentOptions['tmp_name'])) || (!$already_uploaded && !is_uploaded_file($attachmentOptions['tmp_name'])))
-	{
-		$attachmentOptions['errors'] = array('could_not_upload');
-		return false;
-	}
 
 	// These are the only valid image types for SMF.
 	$validImageTypes = array(
@@ -2099,104 +2073,25 @@ function createAttachment(&$attachmentOptions)
 		14 => 'iff'
 	);
 
-	if (!$file_restricted || $already_uploaded)
-	{
-		$size = @getimagesize($attachmentOptions['tmp_name']);
-		list ($attachmentOptions['width'], $attachmentOptions['height']) = $size;
+	// If this is an image we need to set a few additional parameters.
+	$size = @getimagesize($attachmentOptions['tmp_name']);
+	list ($attachmentOptions['width'], $attachmentOptions['height']) = $size;
 
-		// If it's an image get the mime type right.
-		if (empty($attachmentOptions['mime_type']) && $attachmentOptions['width'])
-		{
-			// Got a proper mime type?
-			if (!empty($size['mime']))
-				$attachmentOptions['mime_type'] = $size['mime'];
-			// Otherwise a valid one?
-			elseif (isset($validImageTypes[$size[2]]))
-				$attachmentOptions['mime_type'] = 'image/' . $validImageTypes[$size[2]];
-		}
+	// If it's an image get the mime type right.
+	if (empty($attachmentOptions['mime_type']) && $attachmentOptions['width'])
+	{
+		// Got a proper mime type?
+		if (!empty($size['mime']))
+			$attachmentOptions['mime_type'] = $size['mime'];
+		// Otherwise a valid one?
+		elseif (isset($validImageTypes[$size[2]]))
+			$attachmentOptions['mime_type'] = 'image/' . $validImageTypes[$size[2]];
 	}
 
 	// Get the hash if no hash has been given yet.
 	if (empty($attachmentOptions['file_hash']))
 		$attachmentOptions['file_hash'] = getAttachmentFilename($attachmentOptions['name'], false, null, true);
 
-	// Is the file too big?
-	if (!empty($modSettings['attachmentSizeLimit']) && $attachmentOptions['size'] > $modSettings['attachmentSizeLimit'] * 1024)
-		$attachmentOptions['errors'][] = 'too_large';
-
-	if (!empty($modSettings['attachmentCheckExtensions']))
-	{
-		$allowed = explode(',', strtolower($modSettings['attachmentExtensions']));
-		foreach ($allowed as $k => $dummy)
-			$allowed[$k] = trim($dummy);
-
-		if (!in_array(strtolower(substr(strrchr($attachmentOptions['name'], '.'), 1)), $allowed))
-			$attachmentOptions['errors'][] = 'bad_extension';
-	}
-
-	if (!empty($modSettings['attachmentDirSizeLimit']))
-	{
-		// Make sure the directory isn't full.
-		$dirSize = 0;
-		$dir = @opendir($attach_dir) or fatal_lang_error('cant_access_upload_path', 'critical');
-		while ($file = readdir($dir))
-		{
-			if ($file == '.' || $file == '..')
-				continue;
-
-			if (preg_match('~^post_tmp_\d+_\d+$~', $file) != 0)
-			{
-				// Temp file is more than 5 hours old!
-				if (filemtime($attach_dir . '/' . $file) < time() - 18000)
-					@unlink($attach_dir . '/' . $file);
-				continue;
-			}
-
-			$dirSize += filesize($attach_dir . '/' . $file);
-		}
-		closedir($dir);
-
-		// Too big!  Maybe you could zip it or something...
-		if ($attachmentOptions['size'] + $dirSize > $modSettings['attachmentDirSizeLimit'] * 1024)
-			$attachmentOptions['errors'][] = 'directory_full';
-		// Soon to be too big - warn the admins...
-		elseif (!isset($modSettings['attachment_full_notified']) && $modSettings['attachmentDirSizeLimit'] > 4000 && $attachmentOptions['size'] + $dirSize > ($modSettings['attachmentDirSizeLimit'] - 2000) * 1024)
-		{
-			require_once($sourcedir . '/Subs-Admin.php');
-			emailAdmins('admin_attachments_full');
-			updateSettings(array('attachment_full_notified' => 1));
-		}
-	}
-
-	// Check if the file already exists.... (for those who do not encrypt their filenames...)
-	if (empty($modSettings['attachmentEncryptFilenames']))
-	{
-		// Make sure they aren't trying to upload a nasty file.
-		$disabledFiles = array('con', 'com1', 'com2', 'com3', 'com4', 'prn', 'aux', 'lpt1', '.htaccess', 'index.php');
-		if (in_array(strtolower(basename($attachmentOptions['name'])), $disabledFiles))
-			$attachmentOptions['errors'][] = 'bad_filename';
-
-		// Check if there's another file with that name...
-		$request = $smcFunc['db_query']('', '
-			SELECT id_attach
-			FROM {db_prefix}attachments
-			WHERE filename = {string:filename}
-			LIMIT 1',
-			array(
-				'filename' => strtolower($attachmentOptions['name']),
-			)
-		);
-		if ($smcFunc['db_num_rows']($request) > 0)
-			$attachmentOptions['errors'][] = 'taken_filename';
-		$smcFunc['db_free_result']($request);
-	}
-
-	if (!empty($attachmentOptions['errors']))
-		return false;
-
-	if (!is_writable($attach_dir))
-		fatal_lang_error('attachments_no_write', 'critical');
-
 	// Assuming no-one set the extension let's take a look at it.
 	if (empty($attachmentOptions['fileext']))
 	{
@@ -2221,10 +2116,15 @@ function createAttachment(&$attachmentOptions)
 	);
 	$attachmentOptions['id'] = $smcFunc['db_insert_id']('{db_prefix}attachments', 'id_attach');
 
+	// @todo Add an error here maybe?
 	if (empty($attachmentOptions['id']))
 		return false;
 
-	// If it's not approved add to the approval queue.
+	// Now that we have the attach id, let's rename this sucker and finish up.
+	$attachmentOptions['destination'] = getAttachmentFilename(basename($attachmentOptions['name']), $attachmentOptions['id'], $id_folder, false, $attachmentOptions['file_hash']);
+	rename($attachmentOptions['tmp_name'], $attachmentOptions['destination']);
+
+	// If it's not approved then add to the approval queue.
 	if (!$attachmentOptions['approved'])
 		$smcFunc['db_insert']('',
 			'{db_prefix}approval_queue',
@@ -2237,99 +2137,11 @@ function createAttachment(&$attachmentOptions)
 			array()
 		);
 
-	$attachmentOptions['destination'] = getAttachmentFilename(basename($attachmentOptions['name']), $attachmentOptions['id'], $id_folder, false, $attachmentOptions['file_hash']);
-
-	if ($already_uploaded)
-		rename($attachmentOptions['tmp_name'], $attachmentOptions['destination']);
-	elseif (!move_uploaded_file($attachmentOptions['tmp_name'], $attachmentOptions['destination']))
-		fatal_lang_error('attach_timeout', 'critical');
-
-	// Attempt to chmod it.
-	@chmod($attachmentOptions['destination'], 0644);
-
-	$size = @getimagesize($attachmentOptions['destination']);
-	list ($attachmentOptions['width'], $attachmentOptions['height']) = empty($size) ? array(null, null, null) : $size;
-
-	// We couldn't access the file before...
-	if ($file_restricted)
-	{
-		// Have a go at getting the right mime type.
-		if (empty($attachmentOptions['mime_type']) && $attachmentOptions['width'])
-		{
-			if (!empty($size['mime']))
-				$attachmentOptions['mime_type'] = $size['mime'];
-			elseif (isset($validImageTypes[$size[2]]))
-				$attachmentOptions['mime_type'] = 'image/' . $validImageTypes[$size[2]];
-		}
-
-		if (!empty($attachmentOptions['width']) && !empty($attachmentOptions['height']))
-			$smcFunc['db_query']('', '
-				UPDATE {db_prefix}attachments
-				SET
-					width = {int:width},
-					height = {int:height},
-					mime_type = {string:mime_type}
-				WHERE id_attach = {int:id_attach}',
-				array(
-					'width' => (int) $attachmentOptions['width'],
-					'height' => (int) $attachmentOptions['height'],
-					'id_attach' => $attachmentOptions['id'],
-					'mime_type' => empty($attachmentOptions['mime_type']) ? '' : $attachmentOptions['mime_type'],
-				)
-			);
-	}
-
-	// Security checks for images
-	// Do we have an image? If yes, we need to check it out!
-	if (isset($validImageTypes[$size[2]]))
-	{
-		if (!checkImageContents($attachmentOptions['destination'], !empty($modSettings['attachment_image_paranoid'])))
-		{
-			// It's bad. Last chance, maybe we can re-encode it?
-			if (empty($modSettings['attachment_image_reencode']) || (!reencodeImage($attachmentOptions['destination'], $size[2])))
-			{
-				// Nothing to do: not allowed or not successful re-encoding it.
-				require_once($sourcedir . '/ManageAttachments.php');
-				removeAttachments(array(
-					'id_attach' => $attachmentOptions['id']
-				));
-				$attachmentOptions['id'] = null;
-				$attachmentOptions['errors'][] = 'bad_attachment';
-
-				return false;
-			}
-			// Success! However, successes usually come for a price:
-			// we might get a new format for our image...
-			$old_format = $size[2];
-			$size = @getimagesize($attachmentOptions['destination']);
-			if (!(empty($size)) && ($size[2] != $old_format))
-			{
-				// Let's update the image information
-				// @todo This is becoming a mess: we keep coming back and update the database,
-				// instead of getting it right the first time.
-				if (isset($validImageTypes[$size[2]]))
-				{
-					$attachmentOptions['mime_type'] = 'image/' . $validImageTypes[$size[2]];
-					$smcFunc['db_query']('', '
-						UPDATE {db_prefix}attachments
-						SET
-							mime_type = {string:mime_type}
-						WHERE id_attach = {int:id_attach}',
-						array(
-							'id_attach' => $attachmentOptions['id'],
-							'mime_type' => $attachmentOptions['mime_type'],
-						)
-					);
-				}
-			}
-		}
-	}
-
-	if (!empty($attachmentOptions['skip_thumbnail']) || (empty($attachmentOptions['width']) && empty($attachmentOptions['height'])))
+	if (empty($modSettings['attachmentThumbnails']) || (empty($attachmentOptions['width']) && empty($attachmentOptions['height'])))
 		return true;
 
 	// Like thumbnails, do we?
-	if (!empty($modSettings['attachmentThumbnails']) && !empty($modSettings['attachmentThumbWidth']) && !empty($modSettings['attachmentThumbHeight']) && ($attachmentOptions['width'] > $modSettings['attachmentThumbWidth'] || $attachmentOptions['height'] > $modSettings['attachmentThumbHeight']))
+	if (!empty($modSettings['attachmentThumbWidth']) && !empty($modSettings['attachmentThumbHeight']) && ($attachmentOptions['width'] > $modSettings['attachmentThumbWidth'] || $attachmentOptions['height'] > $modSettings['attachmentThumbHeight']))
 	{
 		if (createThumbnail($attachmentOptions['destination'], $modSettings['attachmentThumbWidth'], $modSettings['attachmentThumbHeight']))
 		{
@@ -2380,6 +2192,150 @@ function createAttachment(&$attachmentOptions)
 			}
 		}
 	}
+	return true;
+}
+
+/**
+ * Performs various checks on an uploaded file.
+ * - Requires that $_SESSION['temp_attachments'][$attachID] be properly populated.
+ *
+ * @param $attachID
+ */
+function attachmentChecks($attachID)
+{
+	global $modSettings, $context, $sourcedir, $smcFunc;
+
+	// No data or missing data .... Not necessarily needed, but in case a mod author missed something.
+	if ( empty($_SESSION['temp_attachments'][$attachID]))
+		$errror = '$_SESSION[\'temp_attachments\'][$attachID]';
+	elseif (empty($attachID))
+		$errror = '$attachID';
+	elseif (empty($context['attachments']))
+		$errror = '$context[\'attachments\']';
+	elseif (empty($context['attach_dir']))
+		$errror = '$context[\'attach_dir\']';
+		
+	// Let's get their attention.
+	if (!empty($error))
+		fatal_lang_error('attach_check_nag', 'debug', array($error));
+
+	// These are the only valid image types for SMF.
+	$validImageTypes = array(
+		1 => 'gif',
+		2 => 'jpeg',
+		3 => 'png',
+		5 => 'psd',
+		6 => 'bmp',
+		7 => 'tiff',
+		8 => 'tiff',
+		9 => 'jpeg',
+		14 => 'iff'
+	);
+
+	// Just in case this slipped by the first checks, we stop it here and now
+	if ($_SESSION['temp_attachments'][$attachID]['size'] == 0)
+	{
+		$_SESSION['temp_attachments'][$attachID]['errors'][] = 'attach_0_byte_file';
+		return false;
+	}
+
+	// First, the dreaded security check. Sorry folks, but this can't be avoided
+	$size = @getimagesize($_SESSION['temp_attachments'][$attachID]['tmp_name']);
+	if (isset($validImageTypes[$size[2]]))
+	{
+		require_once($sourcedir . '/Subs-Graphics.php');
+		if (!checkImageContents($_SESSION['temp_attachments'][$attachID]['tmp_name'], !empty($modSettings['attachment_image_paranoid'])))
+		{
+			// It's bad. Last chance, maybe we can re-encode it?
+			if (empty($modSettings['attachment_image_reencode']) || (!reencodeImage($_SESSION['temp_attachments'][$attachID]['tmp_name'], $size[2])))
+			{
+				// Nothing to do: not allowed or not successful re-encoding it.
+				$_SESSION['temp_attachments'][$attachID]['errors'][] = 'bad_attachment';
+				return false;
+			}
+			// Success! However, successes usually come for a price:
+			// we might get a new format for our image...
+			$old_format = $size[2];
+			$size = @getimagesize($attachmentOptions['tmp_name']);
+			if (!(empty($size)) && ($size[2] != $old_format))
+			{
+				if (isset($validImageTypes[$size[2]]))
+					$_SESSION['temp_attachments'][$attachID]['type'] = 'image/' . $validImageTypes[$size[2]];
+			}
+		}
+	}
+
+	if (!empty($modSettings['attachmentDirSizeLimit']))
+	{
+		// Check the folder size if it hasn't been done already.
+		if (!isset($context['dir_size']))
+		{
+			$request = $smcFunc['db_query']('', '
+				SELECT SUM(size)
+				FROM {db_prefix}attachments',
+				array(
+				)
+			);
+			list ($context['dir_size']) = $smcFunc['db_fetch_row']($request);
+			$smcFunc['db_free_result']($request);
+		}
+
+		$context['dir_size'] += $_SESSION['temp_attachments'][$attachID]['size'];
+
+		// Soon to be too big - warn the admins...
+		if (empty($modSettings['attachment_full_notified']) && $modSettings['attachmentDirSizeLimit'] > 4000 && $context['dir_size'] > ($modSettings['attachmentDirSizeLimit'] - 2000) * 1024)
+		{
+			require_once($sourcedir . '/Subs-Admin.php');
+			emailAdmins('admin_attachments_full');
+			updateSettings(array('attachment_full_notified' => 1));
+		}
+
+		// Too big!  Maybe you could zip it or something...
+		if ($context['dir_size'] > $modSettings['attachmentDirSizeLimit'] * 1024)
+			$_SESSION['temp_attachments'][$attachID]['errors'][] = 'ran_out_of_space';
+	}
+
+	// Is the file too big?
+	$context['attachments']['total_size'] += $_SESSION['temp_attachments'][$attachID]['size'];
+	if (!empty($modSettings['attachmentSizeLimit']) && $_SESSION['temp_attachments'][$attachID]['size'] > $modSettings['attachmentSizeLimit'] * 1024)
+		$_SESSION['temp_attachments'][$attachID]['errors'][] = array('file_too_big', array(comma_format($modSettings['attachmentSizeLimit'], 0)));
+
+	// Check the total upload size for this post...
+	if (!empty($modSettings['attachmentPostLimit']) && $context['attachments']['total_size'] > $modSettings['attachmentPostLimit'] * 1024)
+		$_SESSION['temp_attachments'][$attachID]['errors'][] = array('attach_max_total_file_size', array(comma_format($modSettings['attachmentPostLimit'], 0), comma_format($modSettings['attachmentPostLimit'] - (($context['attachments']['total_size'] - $_SESSION['temp_attachments'][$attachID]['size']) / 1024), 0)));
+
+	// Have we reached the maximum number of files we are allowed?
+	$context['attachments']['quantity']++;
+	
+	// Set a max limit if none exists
+	if (empty($modSettings['attachmentNumPerPostLimit']) && $context['attachments']['quantity'] >= 50)
+		$modSettings['attachmentNumPerPostLimit'] = 50;
+
+	if (!empty($modSettings['attachmentNumPerPostLimit']) && $context['attachments']['quantity'] > $modSettings['attachmentNumPerPostLimit'])
+		$_SESSION['temp_attachments'][$attachID]['errors'][] = array('attachments_limit_per_post', array($modSettings['attachmentNumPerPostLimit']));
+
+	// File extension check
+	if (!empty($modSettings['attachmentCheckExtensions']))
+	{
+		$allowed = explode(',', strtolower($modSettings['attachmentExtensions']));
+		foreach ($allowed as $k => $dummy)
+			$allowed[$k] = trim($dummy);
+
+		if (!in_array(strtolower(substr(strrchr($_SESSION['temp_attachments'][$attachID]['name'], '.'), 1)), $allowed))
+		{
+			$allowed_extensions = strtr(strtolower($modSettings['attachmentExtensions']), array(',' => ', '));
+			$_SESSION['temp_attachments'][$attachID]['errors'][] = array('cant_upload_type', array($allowed_extensions));
+		}
+	}
+
+	// back up to the previous one if there's been an error.
+	if (!empty($_SESSION['temp_attachments'][$attachID]['errors']))
+	{
+		$context['dir_size'] -= $_SESSION['temp_attachments'][$attachID]['size'];
+		$context['attachments']['total_size'] -= $_SESSION['temp_attachments'][$attachID]['size'];
+		$context['attachments']['quantity']--;
+		return false;
+	}
 
 	return true;
 }

+ 4 - 4
Sources/Subs.php

@@ -2974,7 +2974,7 @@ function setupThemeContext($forceload = false)
  * @param bool $in_use Set to true to account for current memory usage of the script
  * @return bool, true if we have at least the needed memory
  */
-function setMemoryLimit($needed, $in_use = false) 
+function setMemoryLimit($needed, $in_use = false)
 {
 	// everything in bytes
 	$memory_used = 0;
@@ -3004,9 +3004,9 @@ function setMemoryLimit($needed, $in_use = false)
  * @param string $val The byte string, like 256M or 1G
  * @return integer The string converted to a proper integer in bytes
  */
-function memoryReturnBytes($val) 
+function memoryReturnBytes($val)
 {
-	if (is_integer($val)) 
+	if (is_integer($val))
 		return $val;
 	
 	// Separate the number from the designator
@@ -3015,7 +3015,7 @@ function memoryReturnBytes($val)
 	$last = strtolower(substr($val, -1));
 	
 	// convert to bytes
-	switch ($last) 
+	switch ($last)
 	{
 		case 'g':
 			$num *= 1024;

+ 28 - 0
Themes/default/Errors.template.php

@@ -206,4 +206,32 @@ function template_show_file()
 </html>';
 }
 
+function template_attachment_errors()
+{
+	global $context, $scripturl, $txt;
+
+	echo '
+	<div>
+		<div class="cat_bar">
+			<h3 class="catbg">
+				', $txt['attach_error_title'], '
+			</h3>
+		</div>
+		<div class="windowbg">
+			<span class="topslice"><span></span></span>
+			<div class="padding">
+				<div class="noticebox" />', 
+					$context['error_message'], '
+				</div>
+				<hr class="hrcolor" />
+				<a class="button_link" href="', $scripturl, $context['back_link'], '">', $txt['back'], '</a>
+				<span style="float: right; margin:.5em;"></span>
+				<a class="button_link" href="', $scripturl, $context['redirect_link'], '">', $txt['attach_continue'], '</a>
+				<br class="clear_right" />
+			</div>
+			<span class="botslice"><span></span></span>
+		</div>
+	</div>';
+}
+
 ?>

+ 2 - 2
Themes/default/GenericList.template.php

@@ -100,13 +100,13 @@ function template_show_list($list_id = null)
 				$col_header['class'] = 'last_th';
 
 			echo '
-					<th scope="col"', empty($col_header['class']) ? '' : ' class="' . $col_header['class'] . '"', empty($col_header['style']) ? '' : ' style="' . $col_header['style'] . '"', empty($col_header['colspan']) ? '' : ' colspan="' . $col_header['colspan'] . '"', '>', empty($col_header['href']) ? '' : '<a href="' . $col_header['href'] . '" rel="nofollow">', empty($col_header['label']) ? '&nbsp;' : $col_header['label'], empty($col_header['href']) ? '' : '</a>', empty($col_header['sort_image']) ? '' : ' <img src="' . $settings['images_url'] . '/sort_' . $col_header['sort_image'] . '.png" alt="" />', '</th>';
+					<th scope="col"', empty($col_header['class']) ? '' : ' class="' . $col_header['class'] . '"', empty($col_header['style']) ? '' : ' style="' . $col_header['style'] . '"', empty($col_header['colspan']) ? '' : ' colspan="' . $col_header['colspan'] . '"', '>', empty($col_header['href']) ? '' : '<a href="' . $col_header['href'] . '" rel="nofollow">', empty($col_header['label']) ? '&nbsp;' : $col_header['label'], empty($col_header['href']) ? '' : (empty($col_header['sort_image']) ? '</a>' : ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $col_header['sort_image'] . '.png" alt="" /></a>'), '</th>';
 		}
 
 		echo '
 				</tr>
 			</thead>';
-	}
+	} 
 
 		echo '
 			<tbody>';

+ 11 - 13
Themes/default/GenericMenu.template.php

@@ -37,9 +37,7 @@ function template_generic_menu_sidebar_above()
 		if ($firstSection && !empty($menu_context['can_toggle_drop_down']))
 		{
 			echo '
-						<span class="ie6_header floatleft">
-							<a href="', $menu_context['toggle_url'], '">', $section['title'],'<img style="margin: 0 5px; vertical-align: middle;" src="', $context['menu_image_path'], '/change_menu', $context['right_to_left'] ? '' : '2', '.png" alt="!" /></a>
-						</span>';
+							<a href="', $menu_context['toggle_url'], '">', $section['title'],'<img style="margin: 0 5px; vertical-align: middle;" src="', $context['menu_image_path'], '/change_menu', $context['right_to_left'] ? '' : '2', '.png" alt="!" /></a>';
 		}
 		else
 		{
@@ -131,7 +129,7 @@ function template_generic_menu_dropdown_above()
 				<ul>';
 
 		// For every area of this section show a link to that area (bold if it's currently selected.)
-		// Note: Code for additional_items class was deprecated and has been removed. Suggest following up in Sources if required.
+		// @todo Code for additional_items class was deprecated and has been removed. Suggest following up in Sources if required.
 		foreach ($section['areas'] as $i => $area)
 		{
 			// Not supposed to be printed?
@@ -139,7 +137,7 @@ function template_generic_menu_dropdown_above()
 				continue;
 
 			echo '
-					<li ', !empty($area['subsections']) ? ' class="subsections"' : '', '>';
+					<li', !empty($area['subsections']) ? ' class="subsections"' : '', '>';
 
 			echo '
 						<a ', !empty($area['selected']) ? 'class="chosen" ' : '', 'href="', (isset($area['url']) ? $area['url'] : $menu_context['base_url'] . ';area=' . $i), $menu_context['extra_parameters'], '">', $area['icon'], $area['label'], '</a>';
@@ -148,7 +146,7 @@ function template_generic_menu_dropdown_above()
 			if (!empty($area['selected']) && empty($context['tabs']))
 					$context['tabs'] = isset($area['subsections']) ? $area['subsections'] : array();
 
-			// Is there any subsections?
+			// Are there any subsections?
 			if (!empty($area['subsections']))
 			{
 				echo '
@@ -232,15 +230,19 @@ function template_generic_menu_tabs(&$menu_context)
 		// Has a custom URL defined in the main admin structure?
 		if (isset($tab['url']) && !isset($tab_context['tabs'][$id]['url']))
 			$tab_context['tabs'][$id]['url'] = $tab['url'];
+		
 		// Any additional paramaters for the url?
 		if (isset($tab['add_params']) && !isset($tab_context['tabs'][$id]['add_params']))
 			$tab_context['tabs'][$id]['add_params'] = $tab['add_params'];
+		
 		// Has it been deemed selected?
 		if (!empty($tab['is_selected']))
 			$tab_context['tabs'][$id]['is_selected'] = true;
+		
 		// Does it have its own help?
 		if (!empty($tab['help']))
 			$tab_context['tabs'][$id]['help'] = $tab['help'];
+		
 		// Is this the last one?
 		if (!empty($tab['is_last']) && !isset($tab_context['override_last']))
 			$tab_context['tabs'][$id]['is_last'] = true;
@@ -259,17 +261,13 @@ function template_generic_menu_tabs(&$menu_context)
 	// Show an icon and/or a help item?
 	if (!empty($selected_tab['icon']) || !empty($tab_context['icon']) || !empty($selected_tab['help']) || !empty($tab_context['help']))
 	{
-		echo '
-			<span class="ie6_header floatleft">';
-
 		if (!empty($selected_tab['icon']) || !empty($tab_context['icon']))
 			echo '<img src="', $settings['images_url'], '/icons/', !empty($selected_tab['icon']) ? $selected_tab['icon'] : $tab_context['icon'], '" alt="" class="icon" />';
 
 		if (!empty($selected_tab['help']) || !empty($tab_context['help']))
 			echo '<a href="', $scripturl, '?action=helpadmin;help=', !empty($selected_tab['help']) ? $selected_tab['help'] : $tab_context['help'], '" onclick="return reqWin(this.href);" class="help"><img src="', $settings['images_url'], '/helptopics.png" alt="', $txt['help'], '" class="icon" /></a>';
 
-		echo $tab_context['title'], '
-			</span>';
+		echo $tab_context['title'];
 	}
 	else
 	{
@@ -304,13 +302,13 @@ function template_generic_menu_tabs(&$menu_context)
 			{
 				echo '
 			<li>
-				<a class="active firstlevel" href="', isset($tab['url']) ? $tab['url'] : $menu_context['base_url'] . ';area=' . $menu_context['current_area'] . ';sa=' . $sa, $menu_context['extra_parameters'], isset($tab['add_params']) ? $tab['add_params'] : '', '"><span class="firstlevel">', $tab['label'], '</span></a>
+				<a class="active" href="', isset($tab['url']) ? $tab['url'] : $menu_context['base_url'] . ';area=' . $menu_context['current_area'] . ';sa=' . $sa, $menu_context['extra_parameters'], isset($tab['add_params']) ? $tab['add_params'] : '', '">', $tab['label'], '</a>
 			</li>';
 			}
 			else
 				echo '
 			<li>
-				<a class="firstlevel" href="', isset($tab['url']) ? $tab['url'] : $menu_context['base_url'] . ';area=' . $menu_context['current_area'] . ';sa=' . $sa, $menu_context['extra_parameters'], isset($tab['add_params']) ? $tab['add_params'] : '', '"><span class="firstlevel">', $tab['label'], '</span></a>
+				<a href="', isset($tab['url']) ? $tab['url'] : $menu_context['base_url'] . ';area=' . $menu_context['current_area'] . ';sa=' . $sa, $menu_context['extra_parameters'], isset($tab['add_params']) ? $tab['add_params'] : '', '">', $tab['label'], '</a>
 			</li>';
 		}
 

+ 1 - 1
Themes/default/ManageBoards.template.php

@@ -56,7 +56,7 @@ function template_main()
 			<div class="windowbg">
 				<span class="topslice"><span></span></span>
 				<div class="content">
-					<ul id="category_', $category['id'], '" <ul class="reset nolist">';
+					<ul id="category_', $category['id'], '" class="reset nolist">';
 
 		if (!empty($category['move_link']))
 			echo '

+ 1 - 1
Themes/default/ManageLanguages.template.php

@@ -105,7 +105,7 @@ function template_download_language()
 		echo '
 				<tr class="titlebg">
 					<td colspan="4">
-						<img src="', $settings['images_url'], '/sort_down.png" id="toggle_image_', $theme, '" alt="*" />&nbsp;', isset($context['theme_names'][$theme]) ? $context['theme_names'][$theme] : $theme, '
+						<img class="sort" src="', $settings['images_url'], '/sort_down.png" id="toggle_image_', $theme, '" alt="*" />&nbsp;', isset($context['theme_names'][$theme]) ? $context['theme_names'][$theme] : $theme, '
 					</td>
 				</tr>';
 

+ 6 - 6
Themes/default/ManageMembergroups.template.php

@@ -500,11 +500,11 @@ function template_group_members()
 			<table width="100%" class="table_grid">
 				<thead>
 					<tr class="catbg">
-						<th class="first_th"><a href="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : ''), ';sa=members;start=', $context['start'], ';sort=name', $context['sort_by'] == 'name' && $context['sort_direction'] == 'up' ? ';desc' : '', ';group=', $context['group']['id'], '">', $txt['name'], $context['sort_by'] == 'name' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
-						<th><a href="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : ''), ';sa=members;start=', $context['start'], ';sort=email', $context['sort_by'] == 'email' && $context['sort_direction'] == 'up' ? ';desc' : '', ';group=', $context['group']['id'], '">', $txt['email'], $context['sort_by'] == 'email' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
-						<th><a href="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : ''), ';sa=members;start=', $context['start'], ';sort=active', $context['sort_by'] == 'active' && $context['sort_direction'] == 'up' ? ';desc' : '', ';group=', $context['group']['id'], '">', $txt['membergroups_members_last_active'], $context['sort_by'] == 'active' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
-						<th><a href="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : ''), ';sa=members;start=', $context['start'], ';sort=registered', $context['sort_by'] == 'registered' && $context['sort_direction'] == 'up' ? ';desc' : '', ';group=', $context['group']['id'], '">', $txt['date_registered'], $context['sort_by'] == 'registered' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
-						<th ', empty($context['group']['assignable']) ? ' class="last_th" colspan="2"' : '', '><a href="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : ''), ';sa=members;start=', $context['start'], ';sort=posts', $context['sort_by'] == 'posts' && $context['sort_direction'] == 'up' ? ';desc' : '', ';group=', $context['group']['id'], '">', $txt['posts'], $context['sort_by'] == 'posts' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>';
+						<th class="first_th"><a href="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : ''), ';sa=members;start=', $context['start'], ';sort=name', $context['sort_by'] == 'name' && $context['sort_direction'] == 'up' ? ';desc' : '', ';group=', $context['group']['id'], '">', $txt['name'], $context['sort_by'] == 'name' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
+						<th><a href="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : ''), ';sa=members;start=', $context['start'], ';sort=email', $context['sort_by'] == 'email' && $context['sort_direction'] == 'up' ? ';desc' : '', ';group=', $context['group']['id'], '">', $txt['email'], $context['sort_by'] == 'email' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
+						<th><a href="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : ''), ';sa=members;start=', $context['start'], ';sort=active', $context['sort_by'] == 'active' && $context['sort_direction'] == 'up' ? ';desc' : '', ';group=', $context['group']['id'], '">', $txt['membergroups_members_last_active'], $context['sort_by'] == 'active' ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
+						<th><a href="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : ''), ';sa=members;start=', $context['start'], ';sort=registered', $context['sort_by'] == 'registered' && $context['sort_direction'] == 'up' ? ';desc' : '', ';group=', $context['group']['id'], '">', $txt['date_registered'], $context['sort_by'] == 'registered' ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
+						<th ', empty($context['group']['assignable']) ? ' class="last_th" colspan="2"' : '', '><a href="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : ''), ';sa=members;start=', $context['start'], ';sort=posts', $context['sort_by'] == 'posts' && $context['sort_direction'] == 'up' ? ';desc' : '', ';group=', $context['group']['id'], '">', $txt['posts'], $context['sort_by'] == 'posts' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '','</a></th>';
 	if (!empty($context['group']['assignable']))
 		echo '
 						<th class="last_th" width="4%" align="center"><input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" /></th>';
@@ -584,7 +584,7 @@ function template_group_members()
 				<div class="content">
 					<dl class="settings">
 						<dt>
-							<strong><label for="toAdd">', $txt['membergroups_members_add_desc'], ':</strong></label>
+							<strong><label for="toAdd">', $txt['membergroups_members_add_desc'], ':</label></strong>
 						</dt>
 						<dd>
 							<input type="text" name="toAdd" id="toAdd" value="" class="input_text" />

+ 31 - 23
Themes/default/ManageNews.template.php

@@ -56,7 +56,7 @@ function template_edit_news()
 				</tbody>
 			</table>
 			<div class="floatleft padding">
-				<div id="moreNewsItems_link" style="display: none;">[<a href="javascript:void(0);" onclick="addNewsItem(); return false;">', $txt['editnews_clickadd'], '</a>]</div>
+				<div id="moreNewsItems_link" style="display: none;"><a class="button_link" href="javascript:void(0);" onclick="addNewsItem(); return false;">', $txt['editnews_clickadd'], '</a></div>
 				<script type="text/javascript"><!-- // --><![CDATA[
 					document.getElementById("moreNewsItems_link").style.display = "";
 					function addNewsItem()
@@ -82,20 +82,6 @@ function template_email_members()
 {
 	global $context, $settings, $options, $txt, $scripturl;
 
-	// This is some javascript for the simple/advanced toggling stuff.
-	echo '
-	<script type="text/javascript"><!-- // --><![CDATA[
-		function toggleAdvanced(mode)
-		{
-			// What styles are we doing?
-			var divStyle = mode ? "" : "none";
-
-			document.getElementById("advanced_settings_div").style.display = divStyle;
-			document.getElementById("gosimple").style.display = divStyle;
-			document.getElementById("goadvanced").style.display = mode ? "none" : "";
-		}
-	// ]]></script>';
-
 	echo '
 	<div id="admincenter">
 		<form action="', $scripturl, '?action=admin;area=news;sa=mailingcompose" method="post" class="flow_hidden" accept-charset="', $context['character_set'], '">
@@ -132,15 +118,13 @@ function template_email_members()
 			<br />
 
 			<div class="cat_bar">
-				<h3 class="catbg" id="advanced_select_div" style="display: none;">
-					<span class="ie6_header floatleft">
-						<a href="#" onclick="toggleAdvanced(1); return false;" id="goadvanced"><img src="', $settings['images_url'], '/selected.png" alt="', $txt['advanced'], '" />&nbsp;<strong>', $txt['advanced'], '</strong></a>
-						<a href="#" onclick="toggleAdvanced(0); return false;" id="gosimple" style="display: none;"><img src="', $settings['images_url'], '/sort_down.png" alt="', $txt['simple'], '" />&nbsp;<strong>', $txt['simple'], '</strong></a>
-					</span>
+				<h3 class="catbg">
+					<span class="ie6_header floatleft"><strong>', $txt['advanced'], '</strong></span>
+					<img class="panel_toggle" src="', $settings['images_url'], '/', empty($context['show_advanced_options']) ? 'collapse' : 'expand', '.png" id="advanced_panel_toggle" alt="*" />
 				</h3>
 			</div>
 
-			<div class="windowbg2" id="advanced_settings_div" style="display: none;">
+			<div id="advanced_panel_div" class="windowbg2">
 				<span class="topslice"><span></span></span>
 				<div class="content">
 					<dl class="settings">
@@ -206,11 +190,35 @@ function template_email_members()
 	</div>
 	<br class="clear" />';
 
-	// Make the javascript stuff visible.
+	// This is some javascript for the simple/advanced toggling and member suggest
 	echo '
+	<script type="text/javascript"><!-- // --><![CDATA[
+		var oAdvancedPanelToggle = new smc_Toggle({
+			bToggleEnabled: true,
+			bCurrentlyCollapsed: ', empty($context['show_advanced_options']) ? 'true' : 'false', ',
+			aSwappableContainers: [
+				\'advanced_panel_div\'
+			],
+			aSwapImages: [
+				{
+					sId: \'advanced_panel_toggle\',
+					srcExpanded: smf_images_url + \'/collapse.png\',
+					altExpanded: ', JavaScriptEscape($txt['upshrink_description']), ',
+					srcCollapsed: smf_images_url + \'/expand.png\',
+					altCollapsed: ', JavaScriptEscape($txt['upshrink_description']), '
+				}
+			],
+			oThemeOptions: {
+				bUseThemeSettings: ', $context['user']['is_guest'] ? 'false' : 'true', ',
+				sOptionName: \'admin_preferences\',
+				sSessionVar: smf_session_var,
+				sSessionId: smf_session_id,
+				sThemeId: \'1\'
+			}
+		});
+	// ]]></script>
 	<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/suggest.js?fin20"></script>
 	<script type="text/javascript"><!-- // --><![CDATA[
-		document.getElementById("advanced_select_div").style.display = "";
 		var oMemberSuggest = new smc_AutoSuggest({
 			sSelf: \'oMemberSuggest\',
 			sSessionId: smf_session_id,

+ 1 - 1
Themes/default/ManagePaid.template.php

@@ -185,7 +185,7 @@ function template_modify_subscription()
 							</dl>
 						</fieldset>
 					</div>
-					<hr class="hrcolor">
+					<hr class="hrcolor" />
 					<input type="submit" name="save" value="', $txt['paid_settings_save'], '" class="button_submit" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-pms_token_var'], '" value="', $context['admin-pms_token'], '" />

+ 6 - 7
Themes/default/ManagePermissions.template.php

@@ -97,9 +97,8 @@ function template_permission_index()
 		echo '
 			<div class="cat_bar">
 				<h3 class="catbg">
-					<span class="ie6_header floatleft">
-						<img src="', $settings['images_url'], '/', empty($context['show_advanced_options']) ? 'selected' : 'sort_down', '.png" id="permissions_panel_toggle" alt="*" /> ', $txt['permissions_advanced_options'], '
-					</span>
+					<span class="ie6_header">', $txt['permissions_advanced_options'], '</span>
+					<img class="panel_toggle" src="', $settings['images_url'], '/', empty($context['show_advanced_options']) ? 'collapse' : 'expand', '.png" id="permissions_panel_toggle" alt="*" />
 				</h3>
 			</div>
 			<div id="permissions_panel_advanced" class="windowbg">
@@ -202,9 +201,9 @@ function template_permission_index()
 			aSwapImages: [
 				{
 					sId: \'permissions_panel_toggle\',
-					srcExpanded: smf_images_url + \'/sort_down.png\',
+					srcExpanded: smf_images_url + \'/collapse.png\',
 					altExpanded: ', JavaScriptEscape($txt['upshrink_description']), ',
-					srcCollapsed: smf_images_url + \'/selected.png\',
+					srcCollapsed: smf_images_url + \'/expand.png\',
 					altCollapsed: ', JavaScriptEscape($txt['upshrink_description']), '
 				}
 			],
@@ -453,7 +452,7 @@ function template_edit_profiles()
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-mpp_token_var'], '" value="', $context['admin-mpp_token'], '" />
 					<input type="submit" name="create" value="', $txt['permissions_profile_new_create'], '" class="button_submit" />
-					<br class="clear_right />
+					<br class="clear_right" />
 				</div>
 				<span class="botslice"><span></span></span>
 			</div>
@@ -615,7 +614,7 @@ function template_modify_group_simple($type)
 					<tr class="windowbg">
 						<td colspan="2" width="100%" align="left">
 							<a href="#" onclick="return toggleBreakdown(\'', $id_group, '\');">
-								<img src="', $settings['images_url'], '/sort_down.png" id="group_toggle_img_', $id_group, '" alt="*" />&nbsp;<strong>', $permissionGroup['name'], '</strong>
+								<img src="', $settings['images_url'], '/selected_open.png" id="group_toggle_img_', $id_group, '" alt="*" />&nbsp;<strong>', $permissionGroup['name'], '</strong>
 							</a>
 						</td>';
 				if (empty($modSettings['permission_enable_deny']) || $context['group']['id'] == -1)

+ 1 - 1
Themes/default/Memberlist.template.php

@@ -50,7 +50,7 @@ function template_main()
 		if ($column['selected'])
 			echo '
 					<th scope="col" class="', isset($column['class']) ? ' ' . $column['class'] : '', '" style="width: auto;"' . (isset($column['colspan']) ? ' colspan="' . $column['colspan'] . '"' : '') . ' nowrap="nowrap">
-						<a href="' . $column['href'] . '" rel="nofollow">' . $column['label'] . ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" /></a></th>';
+						<a href="' . $column['href'] . '" rel="nofollow">' . $column['label'] . '</a><img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" /></th>';
 		// This is just some column... show the link and be done with it.
 		else
 			echo '

+ 4 - 4
Themes/default/MessageIndex.template.php

@@ -167,15 +167,15 @@ function template_main()
 		{
 			echo '
 					<th scope="col" class="first_th" width="8%" colspan="2">&nbsp;</th>
-					<th scope="col" class="lefttext"><a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=subject', $context['sort_by'] == 'subject' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['subject'], $context['sort_by'] == 'subject' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a> / <a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=starter', $context['sort_by'] == 'starter' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['started_by'], $context['sort_by'] == 'starter' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
-					<th scope="col" width="14%"><a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=replies', $context['sort_by'] == 'replies' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['replies'], $context['sort_by'] == 'replies' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a> / <a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=views', $context['sort_by'] == 'views' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['views'], $context['sort_by'] == 'views' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>';
+					<th scope="col" class="lefttext"><a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=subject', $context['sort_by'] == 'subject' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['subject'], $context['sort_by'] == 'subject' ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a> / <a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=starter', $context['sort_by'] == 'starter' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['started_by'],  $context['sort_by'] == 'starter' ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
+					<th scope="col" width="14%"><a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=replies', $context['sort_by'] == 'replies' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['replies'], $context['sort_by'] == 'replies' ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a> / <a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=views', $context['sort_by'] == 'views' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['views'], $context['sort_by'] == 'views' ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>';
 			// Show a "select all" box for quick moderation?
 			if (empty($context['can_quick_mod']))
 				echo '
-					<th scope="col" class="lefttext last_th" width="22%"><a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=last_post', $context['sort_by'] == 'last_post' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] == 'last_post' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>';
+					<th scope="col" class="lefttext last_th" width="22%"><a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=last_post', $context['sort_by'] == 'last_post' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] == 'last_post' ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>';
 			else
 				echo '
-					<th scope="col" class="lefttext" width="22%"><a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=last_post', $context['sort_by'] == 'last_post' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] == 'last_post' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>';
+					<th scope="col" class="lefttext" width="22%"><a href="', $scripturl, '?board=', $context['current_board'], '.', $context['start'], ';sort=last_post', $context['sort_by'] == 'last_post' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] == 'last_post' ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>';
 
 			// Show a "select all" box for quick moderation?
 			if (!empty($context['can_quick_mod']) && $options['display_quick_mod'] == 1)

+ 49 - 14
Themes/default/Packages.template.php

@@ -602,21 +602,19 @@ function template_browse()
 		echo '
 		<div class="information">', $context['sub_action'] == 'browse' ? $txt['no_packages'] : $txt['no_mods_installed'], '</div>';
 
+	// the advanced (emulation) box, collapsed by default
 	if ($context['sub_action'] == 'browse')
-	echo '
-		<div class="flow_auto">
-			<div class="padding">
-				<a class="button_link" href="#" onclick="document.getElementById(\'advanced_box\').style.display = document.getElementById(\'advanced_box\').style.display == \'\' ? \'none\' : \'\'; return false;">', $txt['package_advanced_button'], '</a>
-			</div>
-		</div>';
-		
-	echo '
+		echo '
+		<br class="clear" />
 		<form action="', $scripturl, '?action=admin;area=packages;sa=browse" method="get">
-			<div id="advanced_box" style="display: none;">
+			<div id="advanced_box" >
 				<div class="cat_bar">
-					<h3 class="catbg">', $txt['package_advanced_options'], '</h3>
+					<h3 class="catbg">
+					<span class="ie6_header floatleft"><strong>', $txt['package_advanced_options'], '</strong></span>
+					<img class="panel_toggle" src="', $settings['images_url'], '/', empty($context['show_advanced_options']) ? 'collapse' : 'expand', '.png" id="advanced_panel_toggle" alt="*" />
+					</h3>
 				</div>
-				<div class="windowbg">
+				<div id="advanced_panel_div" class="windowbg">
 					<span class="topslice"><span></span></span>
 					<div class="content">
 						<p>
@@ -643,9 +641,36 @@ function template_browse()
 			<input type="hidden" name="action" value="admin" />
 			<input type="hidden" name="area" value="packages" />
 			<input type="hidden" name="sa" value="browse" />
-		</form>
+		</form>';
+	
+	echo '
 	</div>
 	<br class="clear" />
+	<script type="text/javascript"><!-- // --><![CDATA[
+		var oAdvancedPanelToggle = new smc_Toggle({
+			bToggleEnabled: true,
+			bCurrentlyCollapsed: ', empty($context['show_advanced_options']) ? 'true' : 'false', ',
+			aSwappableContainers: [
+				\'advanced_panel_div\'
+			],
+			aSwapImages: [
+				{
+					sId: \'advanced_panel_toggle\',
+					srcExpanded: smf_images_url + \'/collapse.png\',
+					altExpanded: ', JavaScriptEscape($txt['upshrink_description']), ',
+					srcCollapsed: smf_images_url + \'/expand.png\',
+					altCollapsed: ', JavaScriptEscape($txt['upshrink_description']), '
+				}
+			],
+			oThemeOptions: {
+				bUseThemeSettings: ', $context['user']['is_guest'] ? 'false' : 'true', ',
+				sOptionName: \'admin_preferences\',
+				sSessionVar: smf_session_var,
+				sSessionId: smf_session_id,
+				sThemeId: \'1\'
+			}
+		});
+	// ]]></script>
 	<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/suggest.js?fin20"></script>
 	<script type="text/javascript"><!-- // --><![CDATA[
 			var oAddVersionSuggest = new smc_AutoSuggest({
@@ -1084,9 +1109,19 @@ function template_install_options()
 						<dd>
 							<input type="text" name="pack_user" id="pack_user" value="', $context['package_ftp_username'], '" size="30" class="input_text" />
 						</dd>
+						<dt>
+							<label for="package_make_backups">', $txt['package_install_options_make_backups'], '</label>
+						</dt>
+						<dd>
+							<input type="checkbox" name="package_make_backups" id="package_make_backups" value="1" class="input_check"', $context['package_make_backups'] ? ' checked="checked"' : '', ' />
+						</dd>
+						<dt>
+							<label for="package_make_full_backups">', $txt['package_install_options_make_full_backups'], '</label>
+						</dt>
+						<dd>
+							<input type="checkbox" name="package_make_full_backups" id="package_make_full_backups" value="1" class="input_check"', $context['package_make_full_backups'] ? ' checked="checked"' : '', ' />
+						</dd>
 					</dl>
-					<label for="package_make_backups"><input type="checkbox" name="package_make_backups" id="package_make_backups" value="1" class="input_check"', $context['package_make_backups'] ? ' checked="checked"' : '', ' /> ', $txt['package_install_options_make_backups'], '</label><br /><br />
-					<label for="package_make_full_backups"><input type="checkbox" name="package_make_full_backups" id="package_make_full_backups" value="1" class="input_check"', $context['package_make_full_backups'] ? ' checked="checked"' : '', ' /> ', $txt['package_install_options_make_full_backups'], '</label><br /><br />
 					<hr class="hrcolor" />
 					<input type="submit" name="save" value="', $txt['save'], '" class="button_submit" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />

+ 41 - 9
Themes/default/PersonalMessage.template.php

@@ -543,13 +543,13 @@ function template_subject_list()
 				<a href="', $scripturl, '?action=pm;view;f=', $context['folder'], ';start=', $context['start'], ';sort=', $context['sort_by'], ($context['sort_direction'] == 'up' ? '' : ';desc'), ($context['current_label_id'] != -1 ? ';l=' . $context['current_label_id'] : ''), '"><img src="', $settings['images_url'], '/im_switch.png" alt="', $txt['pm_change_view'], '" title="', $txt['pm_change_view'], '" width="16" height="16" /></a>
 			</th>
 			<th class="lefttext" width="22%">
-				<a href="', $scripturl, '?action=pm;f=', $context['folder'], ';start=', $context['start'], ';sort=date', $context['sort_by'] == 'date' && $context['sort_direction'] == 'up' ? ';desc' : '', $context['current_label_id'] != -1 ? ';l=' . $context['current_label_id'] : '', '">', $txt['date'], $context['sort_by'] == 'date' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
+				<a href="', $scripturl, '?action=pm;f=', $context['folder'], ';start=', $context['start'], ';sort=date', $context['sort_by'] == 'date' && $context['sort_direction'] == 'up' ? ';desc' : '', $context['current_label_id'] != -1 ? ';l=' . $context['current_label_id'] : '', '">', $txt['date'], $context['sort_by'] == 'date' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
 			</th>
 			<th class="lefttext" width="46%">
-				<a href="', $scripturl, '?action=pm;f=', $context['folder'], ';start=', $context['start'], ';sort=subject', $context['sort_by'] == 'subject' && $context['sort_direction'] == 'up' ? ';desc' : '', $context['current_label_id'] != -1 ? ';l=' . $context['current_label_id'] : '', '">', $txt['subject'], $context['sort_by'] == 'subject' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
+				<a href="', $scripturl, '?action=pm;f=', $context['folder'], ';start=', $context['start'], ';sort=subject', $context['sort_by'] == 'subject' && $context['sort_direction'] == 'up' ? ';desc' : '', $context['current_label_id'] != -1 ? ';l=' . $context['current_label_id'] : '', '">', $txt['subject'], $context['sort_by'] == 'subject' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
 			</th>
 			<th class="lefttext">
-				<a href="', $scripturl, '?action=pm;f=', $context['folder'], ';start=', $context['start'], ';sort=name', $context['sort_by'] == 'name' && $context['sort_direction'] == 'up' ? ';desc' : '', $context['current_label_id'] != -1 ? ';l=' . $context['current_label_id'] : '', '">', ($context['from_or_to'] == 'from' ? $txt['from'] : $txt['to']), $context['sort_by'] == 'name' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
+				<a href="', $scripturl, '?action=pm;f=', $context['folder'], ';start=', $context['start'], ';sort=name', $context['sort_by'] == 'name' && $context['sort_direction'] == 'up' ? ';desc' : '', $context['current_label_id'] != -1 ? ';l=' . $context['current_label_id'] : '', '">', ($context['from_or_to'] == 'from' ? $txt['from'] : $txt['to']), $context['sort_by'] == 'name' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
 			</th>
 			<th align="center" width="4%" class="last_th">
 				<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />
@@ -739,10 +739,12 @@ function template_search()
 			<div class="roundframe">
 				<div class="title_bar">
 					<h4 class="titlebg">
-						<span class="ie6_header floatleft"><a href="javascript:void(0);" onclick="expandCollapseLabels(); return false;"><img src="', $settings['images_url'], '/expand.png" id="expandLabelsIcon" alt="" /></a> <a href="javascript:void(0);" onclick="expandCollapseLabels(); return false;"><strong>', $txt['pm_search_choose_label'], '</strong></a></span>
+						<span class="ie6_header floatleft"><strong>', $txt['pm_search_choose_label'], '</strong></span>
+						<img class="panel_toggle" src="', $settings['images_url'], '/', empty($context['show_advanced_options']) ? 'collapse' : 'expand', '.png" id="advanced_panel_toggle" alt="*" />
 					</h4>
 				</div>
-				<ul id="searchLabelsExpand" class="reset" ', $context['check_all'] ? 'style="display: none;"' : '', '>';
+				<div id="advanced_panel_div">
+				<ul id="searchLabelsExpand" class="reset" >';
 
 			foreach ($context['search_labels'] as $label)
 				echo '
@@ -753,6 +755,7 @@ function template_search()
 
 			echo '
 				</ul>
+				</div>
 				<p>
 					<span class="floatleft"><input type="checkbox" name="all" id="check_all" value="" ', $context['check_all'] ? 'checked="checked"' : '', ' onclick="invertAll(this, this.form, \'searchlabel\');" class="input_check" /><em> <label for="check_all">', $txt['check_all'], '</label></em></span>
 					<input type="submit" name="pm_search" value="', $txt['pm_search_go'], '" class="button_submit" />
@@ -760,6 +763,34 @@ function template_search()
 			</div>
 			<span class="lowerframe"><span></span></span>
 		</fieldset>';
+
+			// Some javascript for the advanced toggling
+			echo '
+		<script type="text/javascript"><!-- // --><![CDATA[
+			var oAdvancedPanelToggle = new smc_Toggle({
+				bToggleEnabled: true,
+				bCurrentlyCollapsed: ', empty($context['show_advanced_options']) ? 'true' : 'false', ',
+				aSwappableContainers: [
+					\'advanced_panel_div\'
+				],
+				aSwapImages: [
+					{
+						sId: \'advanced_panel_toggle\',
+						srcExpanded: smf_images_url + \'/collapse.png\',
+						altExpanded: ', JavaScriptEscape($txt['upshrink_description']), ',
+						srcCollapsed: smf_images_url + \'/expand.png\',
+						altCollapsed: ', JavaScriptEscape($txt['upshrink_description']), '
+					}
+				],
+				oThemeOptions: {
+					bUseThemeSettings: ', $context['user']['is_guest'] ? 'false' : 'true', ',
+					sOptionName: \'admin_preferences\',
+					sSessionVar: smf_session_var,
+					sSessionId: smf_session_id,
+					sThemeId: \'1\'
+				}
+			});
+		// ]]></script>';
 		}
 	}
 
@@ -1227,6 +1258,7 @@ function template_labels()
 	echo '
 		<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 	</form>
+	<br class="clear" />
 	<form action="', $scripturl, '?action=pm;sa=manlabels" method="post" accept-charset="', $context['character_set'], '" style="margin-top: 1ex;">
 		<div class="cat_bar">
 			<h3 class="catbg">', $txt['pm_label_add_new'], '</h3>
@@ -1242,9 +1274,9 @@ function template_labels()
 						<input type="text" id="add_label" name="label" value="" size="30" maxlength="30" class="input_text" />
 					</dd>
 				</dl>
-				<div class="righttext">
-					<input type="submit" name="add" value="', $txt['pm_label_add_new'], '" class="button_submit" />
-				</div>
+				<hr class="hrcolor" />
+				<input type="submit" name="add" value="', $txt['pm_label_add_new'], '" class="button_submit" />
+				<br class="clear_right" />
 			</div>
 			<span class="botslice"><span></span></span>
 		</div>
@@ -1385,7 +1417,7 @@ function template_rules()
 		</tbody>
 		</table>
 		<div class="righttext">
-			[<a href="', $scripturl, '?action=pm;sa=manrules;add;rid=0">', $txt['pm_add_rule'], '</a>]';
+			<a class="button_link" href="', $scripturl, '?action=pm;sa=manrules;add;rid=0">', $txt['pm_add_rule'], '</a>';
 
 	if (!empty($context['rules']))
 		echo '

+ 30 - 7
Themes/default/Post.template.php

@@ -407,8 +407,14 @@ function template_main()
 		foreach ($context['current_attachments'] as $attachment)
 			echo '
 						<dd class="smalltext">
-							<label for="attachment_', $attachment['id'], '"><input type="checkbox" id="attachment_', $attachment['id'], '" name="attach_del[]" value="', $attachment['id'], '"', empty($attachment['unchecked']) ? ' checked="checked"' : '', ' class="input_check" /> ', $attachment['name'], (empty($attachment['approved']) ? ' (' . $txt['awaiting_approval'] . ')' : ''), '</label>
+							<label for="attachment_', $attachment['id'], '"><input type="checkbox" id="attachment_', $attachment['id'], '" name="attach_del[]" value="', $attachment['id'], '"', empty($attachment['unchecked']) ? ' checked="checked"' : '', ' class="input_check" /> ', $attachment['name'], (empty($attachment['approved']) ? ' (' . $txt['awaiting_approval'] . ')' : ''),
+							!empty($modSettings['attachmentPostLimit']) || !empty($modSettings['attachmentSizeLimit']) ? sprintf($txt['attach_kb'], comma_format(round(max($attachment['size'], 1028) / 1028), 0)) : '', '</label>
 						</dd>';
+
+		if (!empty($context['files_in_session_warning']))
+			echo '
+						<dd class="smalltext">', $context['files_in_session_warning'], '</dd>';
+
 		echo '
 					</dl>';
 	}
@@ -417,16 +423,22 @@ function template_main()
 	if ($context['can_post_attachment'])
 	{
 		echo '
-					<dl id="postAttachment2">
+					<dl id="postAttachment2">';
+		
+		// But, only show them if they haven't reached a limit. Or a mod author hasn't hidden them.
+		if ($context['num_allowed_attachments'] > 0 || !empty($context['dont_show_them']))
+		{
+			echo '
 						<dt>
 							', $txt['attach'], ':
 						</dt>
 						<dd class="smalltext">
+							', empty($modSettings['attachmentSizeLimit']) ? '' : ('<input type="hidden" name="MAX_FILE_SIZE" value="' . $modSettings['attachmentSizeLimit'] * 1028 . '" />'), '
 							<input type="file" size="60" name="attachment[]" id="attachment1" class="input_file" /> (<a href="javascript:void(0);" onclick="cleanFileInput(\'attachment1\');">', $txt['clean_attach'], '</a>)';
 
-		// Show more boxes only if they aren't approaching their limit.
-		if ($context['num_allowed_attachments'] > 1)
-			echo '
+			// Show more boxes if they aren't approaching that limit.
+			if ($context['num_allowed_attachments'] > 1)
+				echo '
 							<script type="text/javascript"><!-- // --><![CDATA[
 								var allowed_attachments = ', $context['num_allowed_attachments'], ';
 								var current_attachment = 1;
@@ -438,13 +450,20 @@ function template_main()
 									if (allowed_attachments <= 0)
 										return alert("', $txt['more_attachments_error'], '");
 
-									setOuterHTML(document.getElementById("moreAttachments"), \'<dd class="smalltext"><input type="file" size="60" name="attachment[]" id="attachment\' + current_attachment + \'" class="input_file" /> (<a href="javascript:void(0);" onclick="cleanFileInput(\\\'attachment\' + current_attachment + \'\\\');">', $txt['clean_attach'], '</a>)\' + \'</dd><dd class="smalltext" id="moreAttachments"><a href="#" onclick="addAttachment(); return false;">(', $txt['more_attachments'], ')<\' + \'/a><\' + \'/dd>\');
+									setOuterHTML(document.getElementById("moreAttachments"), \'<dd class="smalltext"><input type="file" size="60" name="attachment[]" id="attachment\' + current_attachment + \'" class="input_file" /> (<a href="javascript:void(0);" onclick="cleanFileInput(\\\'attachment\' + current_attachment + \'\\\');">', $txt['clean_attach'], '<\/a>)\' + \'<\/dd><dd class="smalltext" id="moreAttachments"><a href="#" onclick="addAttachment(); return false;">(', $txt['more_attachments'], ')<\' + \'/a><\' + \'/dd>\');
 
 									return true;
 								}
 							// ]]></script>
 						</dd>
 						<dd class="smalltext" id="moreAttachments"><a href="#" onclick="addAttachment(); return false;">(', $txt['more_attachments'], ')</a></dd>';
+			else
+				echo '
+						</dd>';
+		}
+
+		// Add any template changes for an alternative upload system here.
+		call_integration_hook('integrate_upload_template', array());
 
 		echo '
 						<dd class="smalltext">';
@@ -458,6 +477,10 @@ function template_main()
 			echo '
 							', $txt['attach_restrictions'], ' ', implode(', ', $context['attachment_restrictions']), '<br />';
 
+		if ($context['num_allowed_attachments'] == 0)
+			echo '
+							', $txt['attach_limit_nag'], '<br />';
+
 		if (!$context['can_post_attachment_unapproved'])
 			echo '
 							<span class="alert">', $txt['attachment_requires_approval'], '</span>', '<br />';
@@ -484,8 +507,8 @@ function template_main()
 					<p class="smalltext" id="shortcuts">
 						', isBrowser('is_firefox') ? $txt['shortcuts_firefox'] : $txt['shortcuts'], '
 					</p>
+					<hr class="hrcolor" />
 					<p id="post_confirm_buttons">
-						<hr class="hrcolor" />
 						', template_control_richedit_buttons($context['post_box_name']);
 
 	// Option to delete an event if user is editing one.

+ 8 - 8
Themes/default/Recent.template.php

@@ -133,17 +133,17 @@ function template_unread()
 						<tr class="catbg">
 							<th scope="col" class="first_th" width="8%" colspan="2">&nbsp;</th>
 							<th scope="col">
-								<a href="', $scripturl, '?action=unread', $context['showing_all_topics'] ? ';all' : '', $context['querystring_board_limits'], ';sort=subject', $context['sort_by'] == 'subject' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['subject'], $context['sort_by'] == 'subject' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
+								<a href="', $scripturl, '?action=unread', $context['showing_all_topics'] ? ';all' : '', $context['querystring_board_limits'], ';sort=subject', $context['sort_by'] == 'subject' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['subject'], $context['sort_by'] == 'subject' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
 							</th>
 							<th scope="col" width="14%" align="center">
-								<a href="', $scripturl, '?action=unread', $context['showing_all_topics'] ? ';all' : '', $context['querystring_board_limits'], ';sort=replies', $context['sort_by'] == 'replies' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['replies'], $context['sort_by'] == 'replies' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
+								<a href="', $scripturl, '?action=unread', $context['showing_all_topics'] ? ';all' : '', $context['querystring_board_limits'], ';sort=replies', $context['sort_by'] == 'replies' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['replies'], $context['sort_by'] == 'replies' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
 							</th>';
 
 		// Show a "select all" box for quick moderation?
 		if ($showCheckboxes)
 			echo '
 							<th scope="col" width="22%">
-								<a href="', $scripturl, '?action=unread', $context['showing_all_topics'] ? ';all' : '', $context['querystring_board_limits'], ';sort=last_post', $context['sort_by'] == 'last_post' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] == 'last_post' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
+								<a href="', $scripturl, '?action=unread', $context['showing_all_topics'] ? ';all' : '', $context['querystring_board_limits'], ';sort=last_post', $context['sort_by'] == 'last_post' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] == 'last_post' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
 							</th>
 							<th class="last_th">
 								<input type="checkbox" onclick="invertAll(this, this.form, \'topics[]\');" class="input_check" />
@@ -151,7 +151,7 @@ function template_unread()
 		else
 			echo '
 							<th scope="col" class="smalltext last_th" width="22%">
-								<a href="', $scripturl, '?action=unread', $context['showing_all_topics'] ? ';all' : '', $context['querystring_board_limits'], ';sort=last_post', $context['sort_by'] == 'last_post' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] == 'last_post' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
+								<a href="', $scripturl, '?action=unread', $context['showing_all_topics'] ? ';all' : '', $context['querystring_board_limits'], ';sort=last_post', $context['sort_by'] == 'last_post' && $context['sort_direction'] == 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] == 'last_post' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
 							</th>';
 		echo '
 						</tr>
@@ -317,17 +317,17 @@ function template_replies()
 						<tr class="catbg">
 							<th scope="col" class="first_th" width="8%" colspan="2">&nbsp;</th>
 							<th scope="col">
-								<a href="', $scripturl, '?action=unreadreplies', $context['querystring_board_limits'], ';sort=subject', $context['sort_by'] === 'subject' && $context['sort_direction'] === 'up' ? ';desc' : '', '">', $txt['subject'], $context['sort_by'] === 'subject' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
+								<a href="', $scripturl, '?action=unreadreplies', $context['querystring_board_limits'], ';sort=subject', $context['sort_by'] === 'subject' && $context['sort_direction'] === 'up' ? ';desc' : '', '">', $txt['subject'], $context['sort_by'] === 'subject' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
 							</th>
 							<th scope="col" width="14%" align="center">
-								<a href="', $scripturl, '?action=unreadreplies', $context['querystring_board_limits'], ';sort=replies', $context['sort_by'] === 'replies' && $context['sort_direction'] === 'up' ? ';desc' : '', '">', $txt['replies'], $context['sort_by'] === 'replies' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
+								<a href="', $scripturl, '?action=unreadreplies', $context['querystring_board_limits'], ';sort=replies', $context['sort_by'] === 'replies' && $context['sort_direction'] === 'up' ? ';desc' : '', '">', $txt['replies'], $context['sort_by'] === 'replies' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
 							</th>';
 
 		// Show a "select all" box for quick moderation?
 		if ($showCheckboxes)
 				echo '
 							<th scope="col" width="22%">
-								<a href="', $scripturl, '?action=unreadreplies', $context['querystring_board_limits'], ';sort=last_post', $context['sort_by'] === 'last_post' && $context['sort_direction'] === 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] === 'last_post' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
+								<a href="', $scripturl, '?action=unreadreplies', $context['querystring_board_limits'], ';sort=last_post', $context['sort_by'] === 'last_post' && $context['sort_direction'] === 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] === 'last_post' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
 							</th>
 							<th class="last_th">
 								<input type="checkbox" onclick="invertAll(this, this.form, \'topics[]\');" class="input_check" />
@@ -335,7 +335,7 @@ function template_replies()
 		else
 			echo '
 							<th scope="col" class="last_th" width="22%">
-								<a href="', $scripturl, '?action=unreadreplies', $context['querystring_board_limits'], ';sort=last_post', $context['sort_by'] === 'last_post' && $context['sort_direction'] === 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] === 'last_post' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
+								<a href="', $scripturl, '?action=unreadreplies', $context['querystring_board_limits'], ';sort=last_post', $context['sort_by'] === 'last_post' && $context['sort_direction'] === 'up' ? ';desc' : '', '">', $txt['last_post'], $context['sort_by'] === 'last_post' ? ' <img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a>
 							</th>';
 		echo '
 						</tr>

+ 2 - 2
Themes/default/Who.template.php

@@ -42,8 +42,8 @@ function template_main()
 				<table class="table_grid" cellspacing="0">
 					<thead>
 						<tr class="catbg">
-							<th scope="col" class="lefttext first_th" width="40%"><a href="', $scripturl, '?action=who;start=', $context['start'], ';show=', $context['show_by'], ';sort=user', $context['sort_direction'] != 'down' && $context['sort_by'] == 'user' ? '' : ';asc', '" rel="nofollow">', $txt['who_user'], ' ', $context['sort_by'] == 'user' ? '<img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
-							<th scope="col" class="lefttext" width="10%"><a href="', $scripturl, '?action=who;start=', $context['start'], ';show=', $context['show_by'], ';sort=time', $context['sort_direction'] == 'down' && $context['sort_by'] == 'time' ? ';asc' : '', '" rel="nofollow">', $txt['who_time'], ' ', $context['sort_by'] == 'time' ? '<img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
+							<th scope="col" class="lefttext first_th" width="40%"><a href="', $scripturl, '?action=who;start=', $context['start'], ';show=', $context['show_by'], ';sort=user', $context['sort_direction'] != 'down' && $context['sort_by'] == 'user' ? '' : ';asc', '" rel="nofollow">', $txt['who_user'], $context['sort_by'] == 'user' ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
+							<th scope="col" class="lefttext" width="10%"><a href="', $scripturl, '?action=who;start=', $context['start'], ';show=', $context['show_by'], ';sort=time', $context['sort_direction'] == 'down' && $context['sort_by'] == 'time' ? ';asc' : '', '" rel="nofollow">', $txt['who_time'], $context['sort_by'] == 'time' ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" />' : '', '</a></th>
 							<th scope="col" class="lefttext last_th" width="50%">', $txt['who_action'], '</th>
 						</tr>
 					</thead>

+ 0 - 1
Themes/default/css/admin.css

@@ -407,7 +407,6 @@ span.search_weight
 	width: 40px;
 	padding: 0 0.5em;
 	text-align: right;
-	display: inline-block;
 }
 .search_settings
 {

+ 26 - 7
Themes/default/css/index.css

@@ -134,7 +134,8 @@ input:focus, textarea:focus, button:focus, select:focus
 /* Lotsa new stuff innit */
 /* Nifty input focus styling from Mollyhawk pages. */
 
-input, select, textarea, textarea.editor {
+input, select, textarea, textarea.editor 
+{
 	background: #fff;
 	outline:none !important;
 	border: 1px solid #bbb;
@@ -142,19 +143,25 @@ input, select, textarea, textarea.editor {
 	border-radius: 3px;
 	box-shadow: 0 2px 5px rgba(0,0,0,0.05) inset;
 }
-input:hover, select:hover, textarea:hover, textarea.editor:hover {
+input:hover, select:hover, textarea:hover, textarea.editor:hover 
+{
 	outline:none !important;
 	border: 1px solid #999;
 }
-textarea:hover, textarea.editor:hover {
+textarea:hover, textarea.editor:hover 
+{
 	background: #fbfbfb;
 }
-input:focus, select:focus, textarea:focus, textarea.editor:focus {
+input:focus, select:focus, textarea:focus, textarea.editor:focus 
+{
 	outline:none !important;
 	border: 1px solid #999;
 	box-shadow: 0 2px 5px rgba(0,0,0,0.1) inset;
 }
-select option {padding: 0.1em 0.3em 0.1em 0.3em;}
+select option 
+{
+	padding: 0.1em 0.3em 0.1em 0.3em;
+}
 /* End lotsa new stuff */
 
 .button_link
@@ -166,6 +173,7 @@ select option {padding: 0.1em 0.3em 0.1em 0.3em;}
 	cursor: pointer;
 	font-weight: normal;
 	float: right;
+	border-radius: 3px;
 }
 a.button_link
 { 
@@ -397,6 +405,7 @@ ul.reset, ul.reset li
 	white-space: nowrap;
 	/* Show a scrollbar after about 24 lines. */
 	max-height: 24em;
+	resize: vertical;
 }
 
 /* The "Quote:" and "Code:" header parts... */
@@ -528,7 +537,7 @@ tr.catbg th a:link, tr.catbg th a:visited, tr.catbg2 td a:link, tr.catbg2 td a:v
 }
 .catbg select
 {
-	height: 1.5em;
+	height: 1.8em;
 	font-size: 0.85em;
 }
 
@@ -557,7 +566,7 @@ tr.catbg th a:link, tr.catbg th a:visited, tr.catbg2 td a:link, tr.catbg2 td a:v
 	overflow: hidden;
 	margin-bottom: 1px;
 }
-div.pagesection div.floatright input
+div.pagesection div.floatright input, div.pagesection div.floatright select
 {
 	margin-top: 3px;
 }
@@ -934,6 +943,11 @@ table.table_list a.collapse
 	height: 31px;
 	line-height: 31px;
 }
+.panel_toggle
+{	
+	margin: 8px 5px 0 1em;
+	float: right;
+}
 
 /* The half-round header bars for some tables. */
 .table_grid tr.catbg, .table_grid tr.titlebg
@@ -994,6 +1008,11 @@ table.table_grid thead tr.catbg th
 {
 	white-space: nowrap;
 }
+img.sort
+{
+	margin-bottom: -0.3em;
+	margin-left: .3em;
+}
 
 /* table_grid styles for Profile > Show Permissions. */
 #permissions table.table_grid  td

BIN
Themes/default/images/helptopics.png


BIN
Themes/default/images/post/poll.png


BIN
Themes/default/images/selected_open.png


BIN
Themes/default/images/sort_down.png


BIN
Themes/default/images/sort_up.png


+ 2 - 0
Themes/default/languages/Admin.english.php

@@ -358,6 +358,8 @@ $txt['attachmentPostLimit'] = 'Max attachment size per post';
 $txt['attachmentSizeLimit'] = 'Max size per attachment';
 $txt['attachmentNumPerPostLimit'] = 'Max number of attachments per post';
 $txt['attachment_gd_warning'] = 'The GD module is currently not installed. Image re-encoding is not possible.';
+$txt['attachment_postsize_warning'] = 'The current php.ini setting \'post_max_size\' may not support this.';
+$txt['attachment_filesize_warning'] = 'The current php.ini setting \'upload_max_filesize\' may not support this.';
 $txt['attachment_image_reencode'] = 'Re-encode potentially dangerous image attachments';
 $txt['attachment_image_reencode_note'] = '(requires GD module)';
 $txt['attachment_image_paranoid_warning'] = 'The extensive security checks can result in a large number of rejected attachments.';

+ 2 - 10
Themes/default/languages/Errors.english.php

@@ -34,13 +34,7 @@ $txt['not_enough_posts_karma'] = 'Sorry, you don\'t have enough posts to modify
 $txt['cant_change_own_karma'] = 'Sorry, you are not permitted to modify your own karma.';
 $txt['karma_wait_time'] = 'Sorry, you can\'t repeat a karma action without waiting %1$s %2$s.';
 $txt['feature_disabled'] = 'Sorry, this feature is disabled.';
-$txt['feature_no_exists'] = 'Sorry, this feature doesn\'t exists.';
-$txt['cant_access_upload_path'] = 'Cannot access attachments upload path!';
-$txt['file_too_big'] = 'Your file is too large. The maximum attachment size allowed is %1$d kB.';
-$txt['attach_timeout'] = 'Your attachment couldn\'t be saved. This might happen because it took too long to upload or the file is bigger than the server will allow.<br /><br />Please consult your server administrator for more information.';
-$txt['filename_exists'] = 'Sorry! There is already an attachment with the same filename as the one you tried to upload. Please rename the file and try again.';
-$txt['bad_attachment'] = 'Your attachment has failed security checks and cannot be uploaded. Please consult the forum administrator.';
-$txt['ran_out_of_space'] = 'The upload folder is full. Please try a smaller file and/or contact an administrator.';
+$txt['feature_no_exists'] = 'Sorry, this feature doesn\'t exist.';
 $txt['couldnt_connect'] = 'Could not connect to server or could not find file';
 $txt['no_board'] = 'The board you specified doesn\'t exist';
 $txt['cant_split'] = 'You are not allowed to split topics';
@@ -215,12 +209,10 @@ $txt['email_missing_data'] = 'You must enter something in both the subject and m
 $txt['topic_gone'] = 'The topic or board you are looking for appears to be either missing or off limits to you.';
 $txt['theme_edit_missing'] = 'The file you are trying to edit... can\'t even be found!';
 
-$txt['attachments_no_write'] = 'The attachments upload directory is not writable.  Your attachment or avatar cannot be saved.';
-$txt['attachments_limit_per_post'] = 'You may not upload more than %1$d attachments per post';
-
 $txt['no_dump_database'] = 'Only administrators can make database backups!';
 $txt['pm_not_yours'] = 'The personal message you\'re trying to quote is not your own or does not exist, please go back and try again.';
 $txt['mangled_post'] = 'Mangled form data - please go back and try again.';
+$txt['post_upload_error'] = 'The post data is missing. This error is can be caused by trying to submit to file larger than allowed by the server.  Please contact your administrator if this problem continues.';
 $txt['quoted_post_deleted'] = 'The post you are trying to quote either does not exist, was deleted, or is no longer viewable by you.';
 $txt['pm_too_many_per_hour'] = 'You have exceeded the limit of %1$d personal messages per hour.';
 $txt['labels_too_many'] = 'Sorry, %1$s messages already had the maximum amount of labels allowed!';

+ 1 - 0
Themes/default/languages/ManagePermissions.english.php

@@ -259,6 +259,7 @@ $txt['permissionhelp_view_attachments'] = 'Attachments are files that are attach
 $txt['permissionname_post_attachment'] = 'Post attachments';
 $txt['permissionhelp_post_attachment'] = 'Attachments are files that are attached to posted messages. One message can contain multiple attachments.';
 
+$txt['permissiongroup_simple_disable_censor'] = 'Word Censor';
 $txt['permissiongroup_simple_view_basic_info'] = 'Use basic forum functionality';
 $txt['permissiongroup_simple_use_pm_system'] = 'Contact members using the personal messaging system';
 $txt['permissiongroup_simple_post_calendar'] = 'Post events onto the calendar';

+ 1 - 1
Themes/default/languages/ManageSmileys.english.php

@@ -91,6 +91,6 @@ $txt['icons_edit_icon'] = 'Edit Message Icon';
 $txt['icons_new_icon'] = 'New Message Icon';
 $txt['icons_location_first_icon'] = 'As First Icon';
 $txt['icons_location_after'] = 'After';
-$txt['icons_filename_all_gif'] = 'All files must be &quot;gif&quot; files';
+$txt['icons_filename_all_gif'] = 'All files must be &quot;png&quot; files';
 $txt['icons_no_entries'] = 'There are currently no message icons configured.';
 ?>

+ 37 - 1
Themes/default/languages/Post.english.php

@@ -94,7 +94,7 @@ $txt['attach'] = 'Attach';
 $txt['clean_attach'] = 'Clear Attachment';
 $txt['attached'] = 'Attached';
 $txt['allowed_types'] = 'Allowed file types';
-$txt['cant_upload_type'] = 'You cannot upload that type of file. The only allowed extensions are';
+$txt['cant_upload_type'] = 'You cannot upload that type of file. The only allowed extensions are %1$s.';
 $txt['uncheck_unwatchd_attach'] = 'Uncheck the attachments you no longer want attached';
 $txt['restricted_filename'] = 'That is a restricted filename. Please try a different filename.';
 $txt['topic_locked_no_reply'] = 'Warning: topic is currently/will be locked!<br />Only admins and moderators can reply.';
@@ -194,4 +194,40 @@ $txt['digest_mod_act_move'] = '"%1$s" was moved';
 $txt['digest_mod_act_merge'] = '"%1$s" was merged';
 $txt['digest_mod_act_split'] = '"%1$s" was split';
 
+$txt['attach_error_title'] = 'Error uploading your attachments.';
+$txt['attach_warning'] = 'There was a problem during the uploading of <strong>%1$s</strong>.';
+$txt['attach_check_nag'] = 'Unable to continue due to incomplete data (%1$s).';
+$txt['attach_continue'] = 'Continue';
+$txt['attach_max_total_file_size'] = 'Sorry, you are out of attachment space. The total attachment size allowed per post is %1$s kB. Space remaining is %2$s kB.';
+$txt['attach_folder_warning'] = 'The attachments directory can not be located. Please notify an administrator of this problem.';
+$txt['attach_folder_admin_warning'] = 'The path to the attachments directory (%1$s) is incorrect. Please correct it in the attachment settings.';
+$txt['attach_limit_nag'] = 'Sorry, but you have reached the maximum number of attachments allowed per post.';
+$txt['attach_no_upload'] = 'There was a problem and your attachments could not be uploaded';
+$txt['attach_remaining'] = '%1$d remaining';
+$txt['attach_available'] = '%1$s kB available';
+$txt['attach_kb'] = ' (%1$s kB)';
+$txt['attach_0_byte_file'] = 'This file appears to be empty. Please contact your forum administrator if this continues to be a problem';
+$txt['attached_files_in_session'] = '<em>The above underlined file(s) have been uploaded but will not be attached to this post until it is submitted.</em>';
+
+$txt['attach_php_error'] = 'Due to an error, your attachment could not be uploaded. Please contact the forum administrator if this continues to be a problem.';
+$txt['php_upload_error_1'] = 'The uploaded file exceeds the upload_max_filesize directive in php.ini. Please contact your host if unable to rectify.';
+$txt['php_upload_error_3'] = 'The uploaded file was only partially uploaded. This is a PHP related error. Please contact your host if this problem continues.';
+$txt['php_upload_error_4'] = 'No file was uploaded. This is a PHP related error. Please contact your host if this problem continues.';
+$txt['php_upload_error_6'] = 'Unable to save. Missing a temporary folder. Please contact your host if unable to rectify.';
+$txt['php_upload_error_7'] = 'Failed to write file to disk. This is a PHP related error. Please contact your host if this problem continues.';
+$txt['php_upload_error_8'] = 'A PHP extension stopped the file upload. This is a PHP related error. Please contact your host if this problem continues.';
+$txt['error_temp_attachments_new'] = 'There are attachments which you had previously attached but not posted. These attachments are still attached to this post. This post does need to be submitted before these attachments are either saved or removed. You can do that <a href="#postAttachment">here</a>';
+$txt['error_temp_attachments_found'] = 'The following attachments were found which you had previously attached to another post but not posted. It is advisable that you do not post until these are either removed or that post has been submited.<br />Click %1$s to remove those attachments. Or %2$s to return to that post.%3$s';
+$txt['error_temp_attachments_lost'] = 'The following attachments were found which you had previously attached to another post but not posted. It is advisable that you do not upload any more attachments until these are removed or that post has been submitedd.<br />Click %1$s to remove these attachments.%2$s';
+$txt['error_temp_attachments_gone'] = 'Those attachments are now removed and you have been returned to the page you were previously on';
+$txt['error_temp_attachments_flushed'] = 'Please note that any files which had been previously attached but not posted. Have now been removed.';
+
+$txt['cant_access_upload_path'] = 'Cannot access attachments upload path!';
+$txt['file_too_big'] = 'Your file is too large. The maximum attachment size allowed is %1$d kB.';
+$txt['attach_timeout'] = 'Your attachment couldn\'t be saved. This might happen because it took too long to upload or the file is bigger than the server will allow.<br /><br />Please consult your server administrator for more information.';
+$txt['bad_attachment'] = 'Your attachment has failed security checks and cannot be uploaded. Please consult the forum administrator.';
+$txt['ran_out_of_space'] = 'The upload folder is full. Please try a smaller file and/or contact an administrator.';
+$txt['attachments_no_write'] = 'The attachments upload directory is not writable.  Your attachment or avatar cannot be saved.';
+$txt['attachments_limit_per_post'] = 'You may not upload more than %1$d attachments per post';
+
 ?>

+ 1 - 1
Themes/default/languages/Search.english.php

@@ -38,7 +38,7 @@ $txt['search_weight_first_message'] = 'Relative search weight for a first messag
 $txt['search_weight_sticky'] = 'Relative search weight for a sticky topic';
 
 $txt['search_settings_desc'] = 'Here you can changes the basic settings of the search function.';
-$txt['search_settings_title'] = 'Search function - settings';
+$txt['search_settings_title'] = 'Search Settings';
 
 $txt['search_weights_desc'] = 'Here you can change the individual components of the relevance rating. ';
 $txt['search_weights_title'] = 'Search - weights';

+ 2 - 2
Themes/default/languages/index.english.php

@@ -654,8 +654,8 @@ $txt['quickmod_split_selected'] = 'Split Selected';
 // In this string, don't use entities. (&amp;, etc.)
 $txt['show_personal_messages'] = 'You have received one or more new personal messages.\\nWould you like to open a new window to view them?';
 
-$txt['previous_next_back'] = '&laquo; previous';
-$txt['previous_next_forward'] = 'next &raquo;';
+$txt['previous_next_back'] = '&171; previous';
+$txt['previous_next_forward'] = 'next &187;';
 
 $txt['movetopic_auto_board'] = '[BOARD]';
 $txt['movetopic_auto_topic'] = '[TOPIC LINK]';

+ 15 - 4
Themes/default/scripts/topic.js

@@ -558,11 +558,22 @@ function expandThumb(thumbID)
 {
 	var img = document.getElementById('thumb_' + thumbID);
 	var link = document.getElementById('link_' + thumbID);
-	var tmp = img.src;
+	
+	// save the currently displayed image attributes
+	var tmp_src = img.src;
+	var tmp_height = img.style.height;
+	var tmp_width = img.style.width;
+	
+	// set the displayed image attributes to the link attributes, this will expand in place
 	img.src = link.href;
-	link.href = tmp;
-	img.style.width = '';
-	img.style.height = '';
+	img.style.width = link.style.width;
+	img.style.height = link.style.height;
+	
+	// place the image attributes back
+	link.href = tmp_src;
+	link.style.width = tmp_width;
+	link.style.height = tmp_height;
+	
 	return false;
 }
 

+ 2 - 2
other/install.php

@@ -247,8 +247,8 @@ function initialize_inputs()
 				@unlink(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $key . '.sql');
 		}
 
-		// Now just redirect to a blank.gif...
-		header('Location: http://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.gif');
+		// Now just redirect to a blank.png...
+		header('Location: http://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
 		exit;
 	}
 

+ 10 - 9
other/install_2-1_mysql.sql

@@ -1186,14 +1186,14 @@ CREATE TABLE {$db_prefix}membergroups (
 
 INSERT INTO {$db_prefix}membergroups
 	(id_group, group_name, description, online_color, min_posts, stars, group_type)
-VALUES (1, '{$default_administrator_group}', '', '#FF0000', -1, '5#staradmin.gif', 1),
-	(2, '{$default_global_moderator_group}', '', '#0000FF', -1, '5#stargmod.gif', 0),
-	(3, '{$default_moderator_group}', '', '', -1, '5#starmod.gif', 0),
-	(4, '{$default_newbie_group}', '', '', 0, '1#star.gif', 0),
-	(5, '{$default_junior_group}', '', '', 50, '2#star.gif', 0),
-	(6, '{$default_full_group}', '', '', 100, '3#star.gif', 0),
-	(7, '{$default_senior_group}', '', '', 250, '4#star.gif', 0),
-	(8, '{$default_hero_group}', '', '', 500, '5#star.gif', 0);
+VALUES (1, '{$default_administrator_group}', '', '#FF0000', -1, '5#staradmin.png', 1),
+	(2, '{$default_global_moderator_group}', '', '#0000FF', -1, '5#stargmod.png', 0),
+	(3, '{$default_moderator_group}', '', '', -1, '5#starmod.png', 0),
+	(4, '{$default_newbie_group}', '', '', 0, '1#star.png', 0),
+	(5, '{$default_junior_group}', '', '', 50, '2#star.png', 0),
+	(6, '{$default_full_group}', '', '', 100, '3#star.png', 0),
+	(7, '{$default_senior_group}', '', '', 250, '4#star.png', 0),
+	(8, '{$default_hero_group}', '', '', 500, '5#star.png', 0);
 # --------------------------------------------------------
 
 #
@@ -1323,7 +1323,8 @@ VALUES ('xx', 'Standard', '0'),
 	('cheesy', 'Cheesy', '8'),
 	('grin', 'Grin', '9'),
 	('sad', 'Sad', '10'),
-	('wink', 'Wink', '11');
+	('wink', 'Wink', '11'),
+	('poll', 'Poll', '12');
 # --------------------------------------------------------
 
 #

+ 9 - 8
other/install_2-1_postgresql.sql

@@ -1577,14 +1577,14 @@ CREATE INDEX {$db_prefix}membergroups_min_posts ON {$db_prefix}membergroups (min
 # Dumping data for table `membergroups`
 #
 
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars, group_type) VALUES (1, '{$default_administrator_group}', '', '#FF0000', -1, '5#staradmin.gif', 1);
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (2, '{$default_global_moderator_group}', '', '#0000FF', -1, '5#stargmod.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (3, '{$default_moderator_group}', '', '', -1, '5#starmod.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (4, '{$default_newbie_group}', '', '', 0, '1#star.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (5, '{$default_junior_group}', '', '', 50, '2#star.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (6, '{$default_full_group}', '', '', 100, '3#star.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (7, '{$default_senior_group}', '', '', 250, '4#star.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (8, '{$default_hero_group}', '', '', 500, '5#star.gif');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars, group_type) VALUES (1, '{$default_administrator_group}', '', '#FF0000', -1, '5#staradmin.png', 1);
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (2, '{$default_global_moderator_group}', '', '#0000FF', -1, '5#stargmod.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (3, '{$default_moderator_group}', '', '', -1, '5#starmod.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (4, '{$default_newbie_group}', '', '', 0, '1#star.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (5, '{$default_junior_group}', '', '', 50, '2#star.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (6, '{$default_full_group}', '', '', 100, '3#star.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (7, '{$default_senior_group}', '', '', 250, '4#star.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (8, '{$default_hero_group}', '', '', 500, '5#star.png');
 # --------------------------------------------------------
 
 #
@@ -1747,6 +1747,7 @@ INSERT INTO {$db_prefix}message_icons (filename, title, icon_order) VALUES ('che
 INSERT INTO {$db_prefix}message_icons (filename, title, icon_order) VALUES ('grin', 'Grin', '9');
 INSERT INTO {$db_prefix}message_icons (filename, title, icon_order) VALUES ('sad', 'Sad', '10');
 INSERT INTO {$db_prefix}message_icons (filename, title, icon_order) VALUES ('wink', 'Wink', '11');
+INSERT INTO {$db_prefix}message_icons (filename, title, icon_order) VALUES ('poll', 'Poll', '12');
 # --------------------------------------------------------
 
 #

+ 9 - 8
other/install_2-1_sqlite.sql

@@ -1288,14 +1288,14 @@ CREATE INDEX {$db_prefix}membergroups_min_posts ON {$db_prefix}membergroups (min
 #
 
 BEGIN TRANSACTION;
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars, group_type) VALUES (1, '{$default_administrator_group}', '', '#FF0000', -1, '5#staradmin.gif', 1);
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (2, '{$default_global_moderator_group}', '', '#0000FF', -1, '5#stargmod.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (3, '{$default_moderator_group}', '', '', -1, '5#starmod.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (4, '{$default_newbie_group}', '', '', 0, '1#star.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (5, '{$default_junior_group}', '', '', 50, '2#star.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (6, '{$default_full_group}', '', '', 100, '3#star.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (7, '{$default_senior_group}', '', '', 250, '4#star.gif');
-INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (8, '{$default_hero_group}', '', '', 500, '5#star.gif');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars, group_type) VALUES (1, '{$default_administrator_group}', '', '#FF0000', -1, '5#staradmin.png', 1);
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (2, '{$default_global_moderator_group}', '', '#0000FF', -1, '5#stargmod.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (3, '{$default_moderator_group}', '', '', -1, '5#starmod.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (4, '{$default_newbie_group}', '', '', 0, '1#star.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (5, '{$default_junior_group}', '', '', 50, '2#star.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (6, '{$default_full_group}', '', '', 100, '3#star.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (7, '{$default_senior_group}', '', '', 250, '4#star.png');
+INSERT INTO {$db_prefix}membergroups (id_group, group_name, description, online_color, min_posts, stars) VALUES (8, '{$default_hero_group}', '', '', 500, '5#star.png');
 COMMIT;
 
 # --------------------------------------------------------
@@ -1439,6 +1439,7 @@ INSERT INTO {$db_prefix}message_icons (filename, title, icon_order) VALUES ('che
 INSERT INTO {$db_prefix}message_icons (filename, title, icon_order) VALUES ('grin', 'Grin', '9');
 INSERT INTO {$db_prefix}message_icons (filename, title, icon_order) VALUES ('sad', 'Sad', '10');
 INSERT INTO {$db_prefix}message_icons (filename, title, icon_order) VALUES ('wink', 'Wink', '11');
+INSERT INTO {$db_prefix}message_icons (filename, title, icon_order) VALUES ('poll', 'Poll', '12');
 COMMIT;
 
 # --------------------------------------------------------

+ 2 - 2
other/upgrade.php

@@ -898,7 +898,7 @@ function initialize_inputs()
 		}
 		closedir($dh);
 
-		header('Location: http://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.gif');
+		header('Location: http://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
 		exit;
 	}
 
@@ -4501,7 +4501,7 @@ function template_upgrade_complete()
 					theCheck.disabled = true;
 				}
 			// ]]></script>
-			<img src="', $boardurl, '/Themes/default/images/blank.gif" alt="" id="delete_upgrader" /><br />';
+			<img src="', $boardurl, '/Themes/default/images/blank.png" alt="" id="delete_upgrader" /><br />';
 
 	echo '<br />
 			If you had any problems with this upgrade, or have any problems using SMF, please don\'t hesitate to <a href="http://www.simplemachines.org/community/index.php">look to us for assistance</a>.<br />