Browse Source

Merge pull request #16 from emanuele45/master

It's me again! :P
Spuds 12 years ago
parent
commit
3d28da963b
41 changed files with 759 additions and 507 deletions
  1. 38 36
      Sources/Admin.php
  2. 1 0
      Sources/Display.php
  3. 1 0
      Sources/Groups.php
  4. 153 25
      Sources/ManageAttachments.php
  5. 1 0
      Sources/Memberlist.php
  6. 1 1
      Sources/PackageGet.php
  7. 1 0
      Sources/PersonalMessage.php
  8. 1 1
      Sources/PostModeration.php
  9. 1 0
      Sources/Profile-Modify.php
  10. 1 0
      Sources/Profile-View.php
  11. 41 0
      Sources/ScheduledTasks.php
  12. 1 0
      Sources/Search.php
  13. 2 0
      Sources/SendTopic.php
  14. 3 3
      Sources/Subs-Members.php
  15. 39 11
      Sources/Subs-Post.php
  16. 1 0
      Sources/Who.php
  17. 2 2
      Themes/default/Display.template.php
  18. 3 0
      Themes/default/Errors.template.php
  19. 1 1
      Themes/default/GenericControls.template.php
  20. 29 19
      Themes/default/ManageMembergroups.template.php
  21. 8 2
      Themes/default/Memberlist.template.php
  22. 2 2
      Themes/default/PersonalMessage.template.php
  23. 31 18
      Themes/default/Profile.template.php
  24. 1 1
      Themes/default/Themes.template.php
  25. 1 1
      Themes/default/index.template.php
  26. 1 0
      Themes/default/languages/Admin.english.php
  27. 68 0
      Themes/default/languages/EmailTemplates.english.php
  28. 3 2
      Themes/default/languages/Errors.english.php
  29. 1 1
      Themes/default/languages/Help.english.php
  30. 2 0
      Themes/default/languages/Modlog.english.php
  31. 0 7
      Themes/default/languages/PersonalMessage.english.php
  32. 12 155
      Themes/default/scripts/fader.js
  33. 162 1
      Themes/default/scripts/profile.js
  34. 0 153
      Themes/default/scripts/script.js
  35. 1 1
      other/install.php
  36. 7 4
      other/install_2-1_mysql.sql
  37. 33 30
      other/install_2-1_postgresql.sql
  38. 6 3
      other/install_2-1_sqlite.sql
  39. 33 9
      other/upgrade_2-1_mysql.sql
  40. 33 9
      other/upgrade_2-1_postgresql.sql
  41. 33 9
      other/upgrade_2-1_sqlite.sql

+ 38 - 36
Sources/Admin.php

@@ -710,47 +710,12 @@ function AdminSearchInternal()
 		'Help', 'ManageMail', 'ManageSettings', 'ManageCalendar', 'ManageBoards', 'ManagePaid', 'ManagePermissions', 'Search',
 		'Login', 'ManageSmileys',
 	);
-	loadLanguage(implode('+', $language_files));
 
 	// All the files we need to include.
 	$include_files = array(
 		'ManageSettings', 'ManageBoards', 'ManageNews', 'ManageAttachments', 'ManageCalendar', 'ManageMail', 'ManagePaid', 'ManagePermissions',
 		'ManagePosts', 'ManageRegistration', 'ManageSearch', 'ManageSearchEngines', 'ManageServer', 'ManageSmileys', 'ManageLanguages',
 	);
-	// @todo add hook to add more include_files here
-	foreach ($include_files as $file)
-		require_once($sourcedir . '/' . $file . '.php');
-
-	/* This is the huge array that defines everything... it's a huge array of items formatted as follows:
-		0 = Language index (Can be array of indexes) to search through for this setting.
-		1 = URL for this indexes page.
-		2 = Help index for help associated with this item (If different from 0)
-	*/
-
-	$search_data = array(
-		// All the major sections of the forum.
-		'sections' => array(
-		),
-		'settings' => array(
-			array('COPPA', 'area=regcenter;sa=settings'),
-			array('CAPTCHA', 'area=securitysettings;sa=spam'),
-		),
-	);
-
-	// Go through the admin menu structure trying to find suitably named areas!
-	foreach ($context[$context['admin_menu_name']]['sections'] as $section)
-	{
-		foreach ($section['areas'] as $menu_key => $menu_item)
-		{
-			$search_data['sections'][] = array($menu_item['label'], 'area=' . $menu_key);
-			if (!empty($menu_item['subsections']))
-				foreach ($menu_item['subsections'] as $key => $sublabel)
-				{
-					if (isset($sublabel['label']))
-						$search_data['sections'][] = array($sublabel['label'], 'area=' . $menu_key . ';sa=' . $key);
-				}
-		}
-	}
 
 	// This is a special array of functions that contain setting data - we query all these to simply pull all setting bits!
 	$settings_search = array(
@@ -787,7 +752,44 @@ function AdminSearchInternal()
 		array('ModifyPruningSettings', 'area=logs;sa=pruning'),
 	);
 
-	// @todo add hook to add more $settings search
+	call_integration_hook('integrate_admin_search', array(&$language_files, &$include_files, &$settings_search));
+
+	loadLanguage(implode('+', $language_files));
+
+	foreach ($include_files as $file)
+		require_once($sourcedir . '/' . $file . '.php');
+
+	/* This is the huge array that defines everything... it's a huge array of items formatted as follows:
+		0 = Language index (Can be array of indexes) to search through for this setting.
+		1 = URL for this indexes page.
+		2 = Help index for help associated with this item (If different from 0)
+	*/
+
+	$search_data = array(
+		// All the major sections of the forum.
+		'sections' => array(
+		),
+		'settings' => array(
+			array('COPPA', 'area=regcenter;sa=settings'),
+			array('CAPTCHA', 'area=securitysettings;sa=spam'),
+		),
+	);
+
+	// Go through the admin menu structure trying to find suitably named areas!
+	foreach ($context[$context['admin_menu_name']]['sections'] as $section)
+	{
+		foreach ($section['areas'] as $menu_key => $menu_item)
+		{
+			$search_data['sections'][] = array($menu_item['label'], 'area=' . $menu_key);
+			if (!empty($menu_item['subsections']))
+				foreach ($menu_item['subsections'] as $key => $sublabel)
+				{
+					if (isset($sublabel['label']))
+						$search_data['sections'][] = array($sublabel['label'], 'area=' . $menu_key . ';sa=' . $key);
+				}
+		}
+	}
+
 	foreach ($settings_search as $setting_area)
 	{
 		// Get a list of their variables.

+ 1 - 0
Sources/Display.php

@@ -997,6 +997,7 @@ function Display()
 		'can_mark_notify' => 'mark_any_notify',
 		'can_send_topic' => 'send_topic',
 		'can_send_pm' => 'pm_send',
+		'can_send_email' => 'send_email_to_members',
 		'can_report_moderator' => 'report_any',
 		'can_moderate_forum' => 'moderate_forum',
 		'can_issue_warning' => 'issue_warning',

+ 1 - 0
Sources/Groups.php

@@ -411,6 +411,7 @@ function MembergroupMembers()
 		'url' => $scripturl . '?action=groups;sa=members;group=' . $context['group']['id'],
 		'name' => $context['group']['name'],
 	);
+	$context['can_send_email'] = allowedTo('send_email_to_members');
 
 	// Load all the group moderators, for fun.
 	$request = $smcFunc['db_query']('', '

+ 153 - 25
Sources/ManageAttachments.php

@@ -607,30 +607,16 @@ function MaintainFiles()
 	list ($context['num_avatars']) = $smcFunc['db_fetch_row']($request);
 	$smcFunc['db_free_result']($request);
 
-	// Find out how big the directory is. We have to loop through all our attachment paths in case there's an old temp file in one of them.
-	$attachmentDirSize = 0;
-	foreach ($attach_dirs as $id => $attach_dir)
-	{
-		$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;
-			}
+	// Check the size of all the directories.
+	$request = $smcFunc['db_query']('', '
+		SELECT SUM(size)
+		FROM {db_prefix}attachments',
+		array(
+		)
+	);
+	list ($attachmentDirSize) = $smcFunc['db_fetch_row']($request);
+	$smcFunc['db_free_result']($request);
 
-			// We're only counting the size of the current attachment directory.
-			if (empty($modSettings['currentAttachmentUploadDir']) || $modSettings['currentAttachmentUploadDir'] == $id)
-				$attachmentDirSize += filesize($attach_dir . '/' . $file);
-		}
-		closedir($dir);
-	}
 	// Divide it into kilobytes.
 	$attachmentDirSize /= 1024;
 
@@ -775,7 +761,7 @@ function RemoveAttachmentBySize()
  */
 function RemoveAttachment()
 {
-	global $modSettings, $txt, $smcFunc;
+	global $txt, $smcFunc, $language;
 
 	checkSession('post');
 
@@ -794,6 +780,8 @@ function RemoveAttachment()
 
 			// And change the message to reflect this.
 			if (!empty($messages))
+			{
+				loadLanguage('index', $language, true);
 				$smcFunc['db_query']('', '
 					UPDATE {db_prefix}messages
 					SET body = CONCAT(body, {string:deleted_message})
@@ -803,6 +791,8 @@ function RemoveAttachment()
 						'deleted_message' => '<br /><br />' . $txt['attachment_delete_admin'],
 					)
 				);
+				loadLanguage('index', $user_info['language'], true);
+			}
 		}
 	}
 
@@ -864,6 +854,7 @@ function removeAttachments($condition, $query_type = '', $return_affected_messag
 	$query_parameter = array(
 		'thumb_attachment_type' => 3,
 	);
+	$do_logging = array();
 
 	if (is_array($condition))
 	{
@@ -888,6 +879,9 @@ function removeAttachments($condition, $query_type = '', $return_affected_messag
 
 			// Add the parameter!
 			$query_parameter[$real_type] = $restriction;
+
+			if ($type == 'do_logging')
+				$do_logging = $condition['id_attach'];
 		}
 		$condition = implode(' AND ', $new_condition);
 	}
@@ -958,6 +952,32 @@ function removeAttachments($condition, $query_type = '', $return_affected_messag
 			)
 		);
 
+	if (!empty($do_logging))
+	{
+		// In order to log the attachments, we really need their message and filename
+		$request = $smcFunc['db_query']('', '
+			SELECT m.id_msg, a.filename
+			FROM {db_prefix}attachments AS a
+				INNER JOIN {db_prefix}messages AS m ON (a.id_msg = m.id_msg)
+			WHERE a.id_attach IN ({array_int:attachments})
+				AND a.attachment_type = {int:attachment_type}',
+			array(
+				'attachments' => $do_logging,
+				'attachment_type' => 0,
+			)
+		);
+
+		while ($row = $smcFunc['db_fetch_assoc']($request))
+			logAction(
+				'remove_attach',
+				array(
+					'message' => $row['id_msg'],
+					'filename' => preg_replace('~&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', $smcFunc['htmlspecialchars']($row['filename'])),
+				)
+			);
+		$smcFunc['db_free_result']($request);
+	}
+
 	if (!empty($attach))
 		$smcFunc['db_query']('', '
 			DELETE FROM {db_prefix}attachments
@@ -1021,6 +1041,7 @@ function RepairAttachments()
 		'attachment_no_msg' => 0,
 		'avatar_no_member' => 0,
 		'wrong_folder' => 0,
+		'files_without_attachment' => 0,
 	);
 
 	$to_fix = !empty($_SESSION['attachments_to_fix']) ? $_SESSION['attachments_to_fix'] : array();
@@ -1439,6 +1460,87 @@ function RepairAttachments()
 		pauseAttachmentMaintenance($to_fix);
 	}
 
+	// What about files who are not recorded in the database?
+	if ($_GET['step'] <= 5)
+	{
+		if (!empty($modSettings['currentAttachmentUploadDir']))
+		{
+			if (!is_array($modSettings['attachmentUploadDir']))
+				$modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
+
+			// Just use the current path for temp files.
+			$attach_dirs = $modSettings['attachmentUploadDir'];
+		}
+		else
+		{
+			$attach_dirs = array($modSettings['attachmentUploadDir']);
+		}
+
+		$current_check = 0;
+		$max_checks = 500;
+		$files_checked = empty($_GET['substep']) ? 0 : $_GET['substep'];
+		foreach ($attach_dirs as $attach_dir)
+		{
+			if ($dir = @opendir($attach_dir))
+			{
+				while ($file = readdir($dir))
+				{
+					if ($file == '.' || $file == '..')
+						continue;
+
+					if ($files_checked <= $current_check)
+					{
+						// Temporary file, get rid of it!
+						if (strpos($file, 'post_tmp_') !== false)
+						{
+							// Temp file is more than 5 hours old!
+							if (filemtime($attach_dir . '/' . $file) < time() - 18000)
+								@unlink($attach_dir . '/' . $file);
+						}
+						// That should be an attachment, let's check if we have it in the database
+						elseif (strpos($file, '_') !== false)
+						{
+							$attachID = (int) substr($file, 0, strpos($file, '_'));
+							if (!empty($attachID))
+							{
+								$request = $smcFunc['db_query']('', '
+									SELECT  id_attach
+									FROM {db_prefix}attachments
+									WHERE id_attach = {int:attachment_id}
+									LIMIT 1',
+									array(
+										'attachment_id' => $attachID,
+									)
+								);
+								if ($smcFunc['db_num_rows']($request) == 0)
+								{
+									if ($fix_errors)
+									{
+										@unlink($attach_dir . '/' . $file);
+									}
+									else
+									{
+										$context['repair_errors']['files_without_attachment']++;
+										$to_fix[] = 'files_without_attachment';
+									}
+								}
+								$smcFunc['db_free_result']($request);
+							}
+						}
+					}
+					$current_check++;
+					if ($current_check - $files_checked >= $max_checks)
+						pauseAttachmentMaintenance($to_fix);
+				}
+				closedir($dir);
+			}
+		}
+
+		$_GET['step'] = 5;
+		$_GET['substep'] = 0;
+		pauseAttachmentMaintenance($to_fix);
+	}
+
 	// Got here we must be doing well - just the template! :D
 	$context['page_title'] = $txt['repair_attachments'];
 	$context[$context['admin_menu_name']]['current_subsection'] = 'maintenance';
@@ -1577,7 +1679,7 @@ function ApproveAttach()
 		ApproveAttachments($attachments);
 	}
 	else
-		removeAttachments(array('id_attach' => $attachments));
+		removeAttachments(array('id_attach' => $attachments, 'do_logging' => true));
 
 	// Return to the topic....
 	redirectexit($redirect);
@@ -1619,6 +1721,9 @@ function ApproveAttachments($attachments)
 	}
 	$smcFunc['db_free_result']($request);
 
+	if (empty($attachments))
+		return 0;
+
 	// Approving an attachment is not hard - it's easy.
 	$smcFunc['db_query']('', '
 		UPDATE {db_prefix}attachments
@@ -1630,6 +1735,29 @@ function ApproveAttachments($attachments)
 		)
 	);
 
+	// In order to log the attachments, we really need their message and filename
+	$request = $smcFunc['db_query']('', '
+		SELECT m.id_msg, a.filename
+		FROM {db_prefix}attachments AS a
+			INNER JOIN {db_prefix}messages AS m ON (a.id_msg = m.id_msg)
+		WHERE a.id_attach IN ({array_int:attachments})
+			AND a.attachment_type = {int:attachment_type}',
+		array(
+			'attachments' => $attachments,
+			'attachment_type' => 0,
+		)
+	);
+
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+		logAction(
+			'approve_attach',
+			array(
+				'message' => $row['id_msg'],
+				'filename' => preg_replace('~&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', $smcFunc['htmlspecialchars']($row['filename'])),
+			)
+		);
+	$smcFunc['db_free_result']($request);
+
 	// Remove from the approval queue.
 	$smcFunc['db_query']('', '
 		DELETE FROM {db_prefix}approval_queue

+ 1 - 0
Sources/Memberlist.php

@@ -174,6 +174,7 @@ function Memberlist()
 	);
 
 	$context['can_send_pm'] = allowedTo('pm_send');
+	$context['can_send_email'] = allowedTo('send_email_to_members');
 
 	// Jump to the sub action.
 	if (isset($subActions[$context['listing_by']]))

+ 1 - 1
Sources/PackageGet.php

@@ -662,7 +662,7 @@ function PackageUpload()
 	{
 		@unlink($destination);
 		loadLanguage('Errors');
-		$txt[$context['package']] = str_replace('{MANAGETHEMEURL}', $scripturl . '?action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id'], $txt[$context['package']]);
+		$txt[$context['package']] = str_replace('{MANAGETHEMEURL}', $scripturl . '?action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id'] . '#theme_install', $txt[$context['package']]);
 		fatal_lang_error('package_upload_error_broken', false, $txt[$context['package']]);
 	}
 	// Is it already uploaded, maybe?

+ 1 - 0
Sources/PersonalMessage.php

@@ -831,6 +831,7 @@ function MessageFolder()
 		$messages_request = false;
 
 	$context['can_send_pm'] = allowedTo('pm_send');
+	$context['can_send_email'] = allowedTo('send_email_to_members');
 	if (!WIRELESS)
 		$context['sub_template'] = 'folder';
 	$context['page_title'] = $txt['pm_inbox'];

+ 1 - 1
Sources/PostModeration.php

@@ -373,7 +373,7 @@ function UnapprovedAttachments()
 			if ($curAction == 'approve')
 				ApproveAttachments($attachments);
 			else
-				removeAttachments(array('id_attach' => $attachments));
+				removeAttachments(array('id_attach' => $attachments, 'do_logging' => true));
 		}
 	}
 

+ 1 - 0
Sources/Profile-Modify.php

@@ -1293,6 +1293,7 @@ function editBuddyIgnoreLists($memID)
 
 	// Can we email the user direct?
 	$context['can_moderate_forum'] = allowedTo('moderate_forum');
+	$context['can_send_email'] = allowedTo('send_email_to_members');
 
 	$subActions = array(
 		'buddies' => array('editBuddies', $txt['editBuddies']),

+ 1 - 0
Sources/Profile-View.php

@@ -30,6 +30,7 @@ function summary($memID)
 	$context += array(
 		'page_title' => sprintf($txt['profile_of_username'], $memberContext[$memID]['name']),
 		'can_send_pm' => allowedTo('pm_send'),
+		'can_send_email' => allowedTo('send_email_to_members'),
 		'can_have_buddy' => allowedTo('profile_identity_own') && !empty($modSettings['enable_buddylist']),
 		'can_issue_warning' => in_array('w', $context['admin_features']) && allowedTo('issue_warning') && $modSettings['warning_settings'][0] == 1,
 	);

+ 41 - 0
Sources/ScheduledTasks.php

@@ -1641,4 +1641,45 @@ function scheduled_paid_subscriptions()
 	return true;
 }
 
+/**
+ * Check for un-posted attachments is something we can do once in a while :P
+ * This function uses opendir cycling through all the attachments
+ */
+function scheduled_remove_temp_attachments()
+{
+	global $modSettings;
+
+	// 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_dirs = $modSettings['attachmentUploadDir'];
+	}
+	else
+	{
+		$attach_dirs = array($modSettings['attachmentUploadDir']);
+	}
+
+	foreach ($attach_dirs as $attach_dir)
+	{
+		$dir = @opendir($attach_dir) or fatal_lang_error('cant_access_upload_path', 'critical');
+		while ($file = readdir($dir))
+		{
+			if ($file == '.' || $file == '..')
+				continue;
+
+			if (strpos($file, 'post_tmp_') !== false)
+			{
+				// Temp file is more than 5 hours old!
+				if (filemtime($attach_dir . '/' . $file) < time() - 18000)
+					@unlink($attach_dir . '/' . $file);
+			}
+		}
+		closedir($dir);
+	}
+}
+
 ?>

+ 1 - 0
Sources/Search.php

@@ -1824,6 +1824,7 @@ function PlushSearch2()
 	$context['page_title'] = $txt['search_results'];
 	$context['get_topics'] = 'prepareSearchContext';
 	$context['can_send_pm'] = allowedTo('pm_send');
+	$context['can_send_email'] = allowedTo('send_email_to_members');
 
 	$context['jump_to'] = array(
 		'label' => addslashes(un_htmlspecialchars($txt['jump_to'])),

+ 2 - 0
Sources/SendTopic.php

@@ -156,6 +156,8 @@ function CustomEmail()
 	if ($user_info['is_guest'] && !empty($modSettings['guest_hideContacts']))
 		fatal_lang_error('no_access', false);
 
+	isAllowedTo('send_email_to_members');
+
 	// Are we sending to a user?
 	$context['form_hidden_vars'] = array();
 	if (isset($_REQUEST['uid']))

+ 3 - 3
Sources/Subs-Members.php

@@ -686,9 +686,6 @@ function registerMember(&$regOptions, $return_errors = false)
 		foreach ($regOptions['theme_vars'] as $var => $value)
 			$theme_vars[$var] = $value;
 
-	// Call an optional function to validate the users' input.
-	call_integration_hook('integrate_register', array(&$regOptions, &$theme_vars));
-
 	// Right, now let's prepare for insertion.
 	$knownInts = array(
 		'date_registered', 'posts', 'id_group', 'last_login', 'instant_messages', 'unread_messages',
@@ -700,6 +697,9 @@ function registerMember(&$regOptions, $return_errors = false)
 		'time_offset',
 	);
 
+	// Call an optional function to validate the users' input.
+	call_integration_hook('integrate_register', array(&$regOptions, &$theme_vars, &$knownInts, &$knownFloats));
+
 	$column_names = array();
 	$values = array();
 	foreach ($regOptions['register_vars'] as $var => $val)

+ 39 - 11
Sources/Subs-Post.php

@@ -1092,9 +1092,12 @@ function sendpm($recipients, $subject, $message, $store_outbox = false, $from =
 		);
 
 		$insertRows = array();
+		$to_list = array();
 		foreach ($all_to as $to)
 		{
 			$insertRows[] = array($id_pm, $to, in_array($to, $recipients['bcc']) ? 1 : 0, isset($deletes[$to]) ? 1 : 0, 1);
+			if (!in_array($to, $recipients['bcc']))
+				$to_list[] = $to;
 		}
 
 		$smcFunc['db_insert']('insert',
@@ -1107,22 +1110,45 @@ function sendpm($recipients, $subject, $message, $store_outbox = false, $from =
 		);
 	}
 
-	censorText($message);
 	censorText($subject);
-	$message = trim(un_htmlspecialchars(strip_tags(strtr(parse_bbc(htmlspecialchars($message), false), array('<br />' => "\n", '</div>' => "\n", '</li>' => "\n", '&#91;' => '[', '&#93;' => ']')))));
+	if (empty($modSettings['disallow_sendBody']))
+	{
+		censorText($message);
+		$message = trim(un_htmlspecialchars(strip_tags(strtr(parse_bbc(htmlspecialchars($message), false), array('<br />' => "\n", '</div>' => "\n", '</li>' => "\n", '&#91;' => '[', '&#93;' => ']')))));
+	}
+	else
+		$message = '';
 
-	foreach ($notifications as $lang => $notification_list)
+	$to_names = array();
+	if (count($to_list) > 1)
 	{
-		// Make sure to use the right language.
-		loadLanguage('index+PersonalMessage', $lang, false);
+		$request = $smcFunc['db_query']('', '
+			SELECT real_name
+			FROM {db_prefix}members
+			WHERE id_member IN ({array_int:to_members})',
+			array(
+				'to_members' => $to_list,
+			)
+		);
+		while ($row = $smcFunc['db_fetch_assoc']($request))
+			$to_names[] = un_htmlspecialchars($row['real_name']);
+		$smcFunc['db_free_result']($request);
+	}
+	$replacements = array(
+		'SUBJECT' => $subject,
+		'MESSAGE' => $message,
+		'SENDER' => un_htmlspecialchars($from['name']),
+		'REPLYLINK' => $scripturl . '?action=pm;sa=send;f=inbox;pmsg=' . $id_pm . ';quote;u=' . $from['id'],
+		'TOLIST' => implode(', ', $to_names),
+	);
+	$email_template = 'new_pm' . (empty($modSettings['disallow_sendBody']) ? '_body' : '') . (!empty($to_names) ? '_tolist' : '');
 
-		// Replace the right things in the message strings.
-		$mailsubject = str_replace(array('SUBJECT', 'SENDER'), array($subject, un_htmlspecialchars($from['name'])), $txt['new_pm_subject']);
-		$mailmessage = str_replace(array('SUBJECT', 'MESSAGE', 'SENDER'), array($subject, $message, un_htmlspecialchars($from['name'])), $txt['pm_email']);
-		$mailmessage .= "\n\n" . $txt['instant_reply'] . ' ' . $scripturl . '?action=pm;sa=send;f=inbox;pmsg=' . $id_pm . ';quote;u=' . $from['id'];
+	foreach ($notifications as $lang => $notification_list)
+	{
+		$mail = loadEmailTemplate($email_template, $replacements, $lang);
 
 		// Off the notification email goes!
-		sendmail($notification_list, $mailsubject, $mailmessage, null, 'p' . $id_pm, false, 2, null, true);
+		sendmail($notification_list, $mail['subject'], $mail['body'], null, 'p' . $id_pm, false, 2, null, true);
 	}
 
 	// Back to what we were on before!
@@ -2272,8 +2298,10 @@ function attachmentChecks($attachID)
 		{
 			$request = $smcFunc['db_query']('', '
 				SELECT SUM(size)
-				FROM {db_prefix}attachments',
+				FROM {db_prefix}attachments
+				WHERE id_folder = {int:folder_id}',
 				array(
+					'folder_id' => empty($modSettings['currentAttachmentUploadDir']) ? 1 : $modSettings['currentAttachmentUploadDir'],
 				)
 			);
 			list ($context['dir_size']) = $smcFunc['db_fetch_row']($request);

+ 1 - 0
Sources/Who.php

@@ -237,6 +237,7 @@ function Who()
 
 	// Some people can't send personal messages...
 	$context['can_send_pm'] = allowedTo('pm_send');
+	$context['can_send_email'] = allowedTo('send_email_to_members');
 
 	// any profile fields disabled?
 	$context['disabled_fields'] = isset($modSettings['disabled_profile_fields']) ? array_flip(explode(',', $modSettings['disabled_profile_fields'])) : array();

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

@@ -366,7 +366,7 @@ function template_main()
 										<li><a href="', $message['member']['website']['url'], '" title="' . $message['member']['website']['title'] . '" target="_blank" class="new_win">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/www_sm.png" alt="' . $message['member']['website']['title'] . '" />' : $txt['www']), '</a></li>';
 
 				// Don't show the email address if they want it hidden.
-				if (in_array($message['member']['show_email'], array('yes', 'yes_permission_override', 'no_through_forum')))
+				if (in_array($message['member']['show_email'], array('yes', 'yes_permission_override', 'no_through_forum')) && $context['can_send_email'])
 					echo '
 										<li><a href="', $scripturl, '?action=emailuser;sa=email;msg=', $message['id'], '" rel="nofollow">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . '" />' : $txt['email']), '</a></li>';
 
@@ -395,7 +395,7 @@ function template_main()
 								<li class="warning">', $context['can_issue_warning'] ? '<a href="' . $scripturl . '?action=profile;area=issuewarning;u=' . $message['member']['id'] . '">' : '', '<img src="', $settings['images_url'], '/warning_', $message['member']['warning_status'], '.png" alt="', $txt['user_warn_' . $message['member']['warning_status']], '" />', $context['can_issue_warning'] ? '</a>' : '', '<span class="warn_', $message['member']['warning_status'], '">', $txt['warn_' . $message['member']['warning_status']], '</span></li>';
 		}
 		// Otherwise, show the guest's email.
-		elseif (!empty($message['member']['email']) && in_array($message['member']['show_email'], array('yes', 'yes_permission_override', 'no_through_forum')))
+		elseif (!empty($message['member']['email']) && in_array($message['member']['show_email'], array('yes', 'yes_permission_override', 'no_through_forum')) && $context['can_send_email'])
 			echo '
 								<li class="email"><a href="', $scripturl, '?action=emailuser;sa=email;msg=', $message['id'], '" rel="nofollow">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . '" />' : $txt['email']), '</a></li>';
 

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

@@ -55,6 +55,9 @@ function template_error_log()
 					</span>
 				</h3>
 			</div>
+			<div class="pagesection floatleft">
+				&nbsp;&nbsp;', $txt['pages'], ': ', $context['page_index'], '
+			</div>
 			<table border="0" cellspacing="1" class="table_grid" id="error_log">
 				<tr>
 					<td colspan="3" class="windowbg">

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

@@ -219,7 +219,7 @@ function template_control_richedit($editor_id, $smileyContainer = null, $bbcCont
 					sButtonBackgroundImageHover: ', JavaScriptEscape($settings['images_url'] . '/bbc/bbc_hoverbg.png'), ',
 					sActiveButtonBackgroundImage: ', JavaScriptEscape($settings['images_url'] . '/bbc/bbc_hoverbg.png'), ',
 					sDividerTemplate: ', JavaScriptEscape('
-						<img src="' . $settings['images_url'] . '/bbc/divider.png" alt="|" style="margin: 0 3px 0 3px;" />
+						<img src="' . $settings['images_url'] . '/bbc/divider.png" alt="|" style="margin: 0 3px;" />
 					'), ',
 					sSelectTemplate: ', JavaScriptEscape('
 						<select name="%selectName%" id="%selectId%" style="margin-bottom: 1ex; font-size: x-small;">

+ 29 - 19
Themes/default/ManageMembergroups.template.php

@@ -500,8 +500,13 @@ 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 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 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>';
+
+	if ($context['can_send_email'])
+		echo '
+						<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>';
+
+	echo '
 						<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>';
@@ -525,28 +530,33 @@ function template_group_members()
 		$alternate = !$alternate;
 		echo '
 					<tr class="', $alternate === true ? 'windowbg' : 'windowbg2', '">
-						<td>', $member['name'], '</td>
+						<td>', $member['name'], '</td>';
+		if ($context['can_send_email'])
+		{
+			echo '
 						<td', $member['show_email'] == 'no_through_forum' && $settings['use_image_buttons'] ? ' align="center"' : '', '>';
 
-		// Is it totally hidden?
-		if ($member['show_email'] == 'no')
-			echo '
-							<em>', $txt['hidden'], '</em>';
-		// ... otherwise they want it hidden but it's not to this person?
-		elseif ($member['show_email'] == 'yes_permission_override')
-			echo '
-							<a href="mailto:', $member['email'], '"><em>', $member['email'], '</em></a>';
-		// ... otherwise it's visible - but only via an image?
-		elseif ($member['show_email'] == 'no_through_forum')
-			echo '
-							<a href="', $scripturl, '?action=emailuser;sa=email;uid=', $member['id'], '" rel="nofollow">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . '" />' : $txt['email']), '</a>';
-		// ... otherwise it must be a 'yes', show it and show it fully.
-		else
+			// Is it totally hidden?
+			if ($member['show_email'] == 'no')
+				echo '
+								<em>', $txt['hidden'], '</em>';
+			// ... otherwise they want it hidden but it's not to this person?
+			elseif ($member['show_email'] == 'yes_permission_override')
+				echo '
+								<a href="mailto:', $member['email'], '"><em>', $member['email'], '</em></a>';
+			// ... otherwise it's visible - but only via an image?
+			elseif ($member['show_email'] == 'no_through_forum')
+				echo '
+								<a href="', $scripturl, '?action=emailuser;sa=email;uid=', $member['id'], '" rel="nofollow">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . '" />' : $txt['email']), '</a>';
+			// ... otherwise it must be a 'yes', show it and show it fully.
+			else
+				echo '
+								<a href="mailto:', $member['email'], '">', $member['email'], '</a>';
 			echo '
-							<a href="mailto:', $member['email'], '">', $member['email'], '</a>';
+						</td>';
+		}
 
 		echo '
-						</td>
 						<td>', $member['last_online'], '</td>
 						<td>', $member['registered'], '</td>
 						<td', empty($context['group']['assignable']) ? ' colspan="2"' : '', '>', $member['posts'], '</td>';

+ 8 - 2
Themes/default/Memberlist.template.php

@@ -44,8 +44,12 @@ function template_main()
 				<tr class="catbg">';
 
 	// Display each of the column headers of the table.
-	foreach ($context['columns'] as $column)
+	foreach ($context['columns'] as $key => $column)
 	{
+		// @TODO maybe find something nicer?
+		if ($key == 'email_address' && !$context['can_send_email'])
+			continue;
+
 		// This is a selected column, so underline it or some such.
 		if ($column['selected'])
 			echo '
@@ -73,7 +77,9 @@ function template_main()
 					<td class="centertext">
 						', $context['can_send_pm'] ? '<a href="' . $member['online']['href'] . '" title="' . $member['online']['text'] . '">' : '', $settings['use_image_buttons'] ? '<img src="' . $member['online']['image_href'] . '" alt="' . $member['online']['text'] . '" class="centericon" />' : $member['online']['label'], $context['can_send_pm'] ? '</a>' : '', '
 					</td>
-					<td class="lefttext">', $member['link'], '</td>
+					<td class="lefttext">', $member['link'], '</td>';
+			if ($context['can_send_email'])
+				echo '
 					<td class="centertext">', $member['show_email'] == 'no' ? '' : '<a href="' . $scripturl . '?action=emailuser;sa=email;uid=' . $member['id'] . '" rel="nofollow"><img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . ' ' . $member['name'] . '" /></a>', '</td>';
 
 		if (!isset($context['disabled_fields']['website']))

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

@@ -307,7 +307,7 @@ function template_folder()
 						<li><a href="', $message['member']['website']['url'], '" title="' . $message['member']['website']['title'] . '" target="_blank" class="new_win">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/www_sm.png" alt="' . $message['member']['website']['title'] . '" />' : $txt['www']), '</a></li>';
 
 					// Don't show the email address if they want it hidden.
-					if (in_array($message['member']['show_email'], array('yes', 'yes_permission_override', 'no_through_forum')))
+					if (in_array($message['member']['show_email'], array('yes', 'yes_permission_override', 'no_through_forum')) && $context['can_send_email'])
 						echo '
 						<li><a href="', $scripturl, '?action=emailuser;sa=email;uid=', $message['member']['id'], '" rel="nofollow">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . '" />' : $txt['email']), '</a></li>';
 
@@ -986,7 +986,7 @@ function template_send()
 
 	// If there were errors for sending the PM, show them.
 	echo '
-				<div class="', empty($context['error_type']) || $context['error_type'] != 'serious' ? 'noticebox' : 'errorbox', '"', empty($context['post_error']['messages']) ? ' style="display: none"' : '', ' id="errors">
+				<div class="errorbox"', empty($context['post_error']['messages']) ? ' style="display: none"' : '', ' id="errors">
 					<dl>
 						<dt>
 							<strong id="error_serious">', $txt['error_while_submitting'] , '</strong>

+ 31 - 18
Themes/default/Profile.template.php

@@ -62,9 +62,9 @@ function template_summary()
 				<div class="username"><h4>', $context['member']['name'], ' <span class="position">', (!empty($context['member']['group']) ? $context['member']['group'] : $context['member']['post_group']), '</span></h4></div>
 				', $context['member']['avatar']['image'], '
 				<ul class="reset">';
-
+	// @TODO fix the <ul> when no fields are visible
 	// What about if we allow email only via the forum??
-	if ($context['member']['show_email'] === 'yes' || $context['member']['show_email'] === 'no_through_forum' || $context['member']['show_email'] === 'yes_permission_override')
+	if ($context['member']['show_email'] === 'yes' || $context['member']['show_email'] === 'no_through_forum' || $context['member']['show_email'] === 'yes_permission_override' && $context['can_send_email'])
 		echo '
 					<li><a href="', $scripturl, '?action=emailuser;sa=email;uid=', $context['member']['id'], '" title="', $context['member']['show_email'] == 'yes' || $context['member']['show_email'] == 'yes_permission_override' ? $context['member']['email'] : '', '" rel="nofollow"><img src="', $settings['images_url'], '/email_sm.png" alt="', $txt['email'], '" /></a></li>';
 
@@ -130,17 +130,20 @@ function template_summary()
 					<dt>', $txt['profile_posts'], ': </dt>
 					<dd>', $context['member']['posts'], ' (', $context['member']['posts_per_day'], ' ', $txt['posts_per_day'], ')</dd>';
 
-	// Only show the email address fully if it's not hidden - and we reveal the email.
-	if ($context['member']['show_email'] == 'yes')
-		echo '
-					<dt>', $txt['email'], ': </dt>
-					<dd><a href="', $scripturl, '?action=emailuser;sa=email;uid=', $context['member']['id'], '">', $context['member']['email'], '</a></dd>';
+	if ($context['can_send_email'])
+	{
+		// Only show the email address fully if it's not hidden - and we reveal the email.
+		if ($context['member']['show_email'] == 'yes')
+			echo '
+						<dt>', $txt['email'], ': </dt>
+						<dd><a href="', $scripturl, '?action=emailuser;sa=email;uid=', $context['member']['id'], '">', $context['member']['email'], '</a></dd>';
 
-	// ... Or if the one looking at the profile is an admin they can see it anyway.
-	elseif ($context['member']['show_email'] == 'yes_permission_override')
-		echo '
-					<dt>', $txt['email'], ': </dt>
-					<dd><em><a href="', $scripturl, '?action=emailuser;sa=email;uid=', $context['member']['id'], '">', $context['member']['email'], '</a></em></dd>';
+		// ... Or if the one looking at the profile is an admin they can see it anyway.
+		elseif ($context['member']['show_email'] == 'yes_permission_override')
+			echo '
+						<dt>', $txt['email'], ': </dt>
+						<dd><em><a href="', $scripturl, '?action=emailuser;sa=email;uid=', $context['member']['id'], '">', $context['member']['email'], '</a></em></dd>';
+	}
 
 	if (!empty($modSettings['titlesEnable']) && !empty($context['member']['title']))
 		echo '
@@ -497,7 +500,9 @@ function template_editBuddies()
 		<table border="0" width="100%" cellspacing="1" cellpadding="4" class="table_grid" align="center">
 			<tr class="catbg">
 				<th class="first_th" scope="col" width="20%">', $txt['name'], '</th>
-				<th scope="col">', $txt['status'], '</th>
+				<th scope="col">', $txt['status'], '</th>';
+	if ($context['can_send_email'])
+		echo '
 				<th scope="col">', $txt['email'], '</th>';
 	
 	// don't show them if they are sdisabled
@@ -526,7 +531,9 @@ function template_editBuddies()
 		echo '
 			<tr class="', $alternate ? 'windowbg' : 'windowbg2', '">
 				<td>', $buddy['link'], '</td>
-				<td align="center"><a href="', $buddy['online']['href'], '"><img src="', $buddy['online']['image_href'], '" alt="', $buddy['online']['label'], '" title="', $buddy['online']['label'], '" /></a></td>
+				<td align="center"><a href="', $buddy['online']['href'], '"><img src="', $buddy['online']['image_href'], '" alt="', $buddy['online']['label'], '" title="', $buddy['online']['label'], '" /></a></td>';
+		if ($context['can_send_email'])
+			echo '
 				<td align="center">', ($buddy['show_email'] == 'no' ? '' : '<a href="' . $scripturl . '?action=emailuser;sa=email;uid=' . $buddy['id'] . '" rel="nofollow"><img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . ' ' . $buddy['name'] . '" /></a>'), '</td>';
 		
 		// If these are off, don't show them
@@ -607,8 +614,11 @@ function template_editIgnoreList()
 		<table border="0" width="100%" cellspacing="1" cellpadding="4" class="table_grid" align="center">
 			<tr class="catbg">
 				<th class="first_th" scope="col" width="20%">', $txt['name'], '</th>
-				<th scope="col">', $txt['status'], '</th>
-				<th scope="col">', $txt['email'], '</th>
+				<th scope="col">', $txt['status'], '</th>';
+	if ($context['can_send_email'])
+		echo '
+				<th scope="col">', $txt['email'], '</th>';
+	echo '
 				<th scope="col">', $txt['icq'], '</th>
 				<th scope="col">', $txt['aim'], '</th>
 				<th scope="col">', $txt['yim'], '</th>
@@ -630,8 +640,11 @@ function template_editIgnoreList()
 		echo '
 			<tr class="', $alternate ? 'windowbg' : 'windowbg2', '">
 				<td>', $member['link'], '</td>
-				<td align="center"><a href="', $member['online']['href'], '"><img src="', $member['online']['image_href'], '" alt="', $member['online']['label'], '" title="', $member['online']['label'], '" /></a></td>
-				<td align="center">', ($member['show_email'] == 'no' ? '' : '<a href="' . $scripturl . '?action=emailuser;sa=email;uid=' . $member['id'] . '" rel="nofollow"><img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . ' ' . $member['name'] . '" /></a>'), '</td>
+				<td align="center"><a href="', $member['online']['href'], '"><img src="', $member['online']['image_href'], '" alt="', $member['online']['label'], '" title="', $member['online']['label'], '" /></a></td>';
+		if ($context['can_send_email'])
+			echo '
+				<td align="center">', ($member['show_email'] == 'no' ? '' : '<a href="' . $scripturl . '?action=emailuser;sa=email;uid=' . $member['id'] . '" rel="nofollow"><img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . ' ' . $member['name'] . '" /></a>'), '</td>';
+		echo '
 				<td align="center">', $member['icq']['link'], '</td>
 				<td align="center">', $member['aim']['link'], '</td>
 				<td align="center">', $member['yim']['link'], '</td>

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

@@ -127,7 +127,7 @@ function template_main()
 		<form action="', $scripturl, '?action=admin;area=theme;sa=install" method="post" accept-charset="', $context['character_set'], '" enctype="multipart/form-data" onsubmit="return confirm(\'', $txt['theme_install_new_confirm'], '\');">
 			<div class="cat_bar">
 				<h3 class="catbg">
-					<span class="ie6_header floatleft"><a href="', $scripturl, '?action=helpadmin;help=theme_install" onclick="return reqWin(this.href);" class="help"><img src="', $settings['images_url'], '/helptopics.png" class="icon" alt="', $txt['help'], '" /></a> ', $txt['theme_install'], '</span>
+					<span class="ie6_header floatleft"><a href="', $scripturl, '?action=helpadmin;help=theme_install" onclick="return reqWin(this.href);" class="help" id="theme_install"><img src="', $settings['images_url'], '/helptopics.png" class="icon" alt="', $txt['help'], '" /></a> ', $txt['theme_install'], '</span>
 				</h3>
 			</div>
 			<div class="windowbg">

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

@@ -299,7 +299,7 @@ function template_body_above()
 	{
 		echo '
 			<form id="search_form" action="', $scripturl, '?action=search2" method="post" accept-charset="', $context['character_set'], '">
-				<input type="text" name="search" value="" class="input_text" />&nbsp';
+				<input type="text" name="search" value="" class="input_text" />&nbsp;';
 		
 		// Using the quick search dropdown?
 		if (!empty($modSettings['search_dropdown']))

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

@@ -442,6 +442,7 @@ $txt['attach_repair_file_size_of_zero'] = '%1$d attachments/avatars have a size
 $txt['attach_repair_attachment_no_msg'] = '%1$d attachments no longer have a message associated with them';
 $txt['attach_repair_avatar_no_member'] = '%1$d avatars no longer have a member associated with them';
 $txt['attach_repair_wrong_folder'] = '%1$d attachments are in the wrong folder';
+$txt['attach_repair_files_without_attachment'] = '%1$d files doesn\'t have a corresponding entri into the database. (These will be deleted)';
 
 $txt['news_title'] = 'News and Newsletters';
 $txt['news_settings_desc'] = 'Here you can change the settings and permissions related to news and newsletters.';

+ 68 - 0
Themes/default/languages/EmailTemplates.english.php

@@ -922,6 +922,74 @@ The following error occurred when processing a paid subscription
 
 {REGARDS}';
 
+/**
+	@additional_params: new_pm
+		SUBJECT: The personal message subject.
+		SENDER:  The user name for the member sending the personal message.
+		REPLYLINK:  The link to directly access the reply page.
+	@description: A notification email sent to the receivers of a personal message
+*/
+$txt['new_pm_subject'] = 'New Personal Message: {SUBJECT}';
+$txt['new_pm_body'] = 'You have just been sent a personal message by {SENDER} on {FORUMNAME}
+
+IMPORTANT: Remember, this is just a notification. Please do not reply to this email.
+
+Reply to this Personal Message here: {REPLYLINK}';
+
+/**
+	@additional_params: new_pm_body
+		SUBJECT: The personal message subject.
+		SENDER:  The user name for the member sending the personal message.
+		MESSAGE:  The text of the personal message.
+		REPLYLINK:  The link to directly access the reply page.
+	@description: A notification email sent to the receivers of a personal message
+*/
+$txt['new_pm_body_subject'] = 'New Personal Message: {SUBJECT}';
+$txt['new_pm_body_body'] = 'You have just been sent a personal message by {SENDER} on {FORUMNAME}
+
+IMPORTANT: Remember, this is just a notification. Please do not reply to this email.
+
+The message they sent you was:
+
+{MESSAGE}
+
+Reply to this Personal Message here: {REPLYLINK}';
+
+/**
+	@additional_params: new_pm_tolist
+		SUBJECT: The personal message subject.
+		SENDER:  The user name for the member sending the personal message.
+		REPLYLINK:  The link to directly access the reply page.
+		TOLIST:  The list of users that will receive the personal message.
+	@description: A notification email sent to the receivers of a personal message
+*/
+$txt['new_pm_tolist_subject'] = 'New Personal Message: {SUBJECT}';
+$txt['new_pm_tolist_body'] = 'You and {TOLIST} have just been sent a personal message by {SENDER} on {FORUMNAME}
+
+IMPORTANT: Remember, this is just a notification. Please do not reply to this email.
+
+Reply to this Personal Message (to the sender only) here: {REPLYLINK}';
+
+/**
+	@additional_params: new_pm_body_tolist
+		SUBJECT: The personal message subject.
+		SENDER:  The user name for the member sending the personal message.
+		MESSAGE:  The text of the personal message.
+		REPLYLINK:  The link to directly access the reply page.
+		TOLIST:  The list of users that will receive the personal message.
+	@description: A notification email sent to the receivers of a personal message
+*/
+$txt['new_pm_body_tolist_subject'] = 'New Personal Message: {SUBJECT}';
+$txt['new_pm_body_tolist_body'] = 'You and {TOLIST} have just been sent a personal message by {SENDER} on {FORUMNAME}
+
+IMPORTANT: Remember, this is just a notification. Please do not reply to this email.
+
+The message they sent you was:
+
+{MESSAGE}
+
+Reply to this Personal Message (to the sender only) here: {REPLYLINK}';
+
 /**
 	@additional_params: happy_birthday
 		REALNAME: The real (display) name of the person receiving the birthday message.

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

@@ -127,6 +127,7 @@ $txt['cannot_search_posts'] = 'You are not allowed to search for posts in this f
 $txt['cannot_send_mail'] = 'You don\'t have the privilege of sending out emails to everyone.';
 $txt['cannot_issue_warning'] = 'Sorry, you do not have permission to issue warnings to members.';
 $txt['cannot_send_topic'] = 'Sorry, but the administrator has disallowed sending topics on this board.';
+$txt['cannot_send_email_to_members'] = 'Sorry, but the administrator has disallowed sending emails on this board.';
 $txt['cannot_split_any'] = 'Splitting just any topic is not allowed in this board.';
 $txt['cannot_view_attachments'] = 'It seems that you are not allowed to download or view attachments on this board.';
 $txt['cannot_view_mlist'] = 'You can\'t view the memberlist because you don\'t have permission to.';
@@ -277,8 +278,8 @@ $txt['package_upload_error_broken'] = 'Package upload failed due to the followin
 $txt['package_get_error_not_found'] = 'The package you are trying to install cannot be located. You may want to manually upload the package to your Packages directory.';
 $txt['package_get_error_missing_xml'] = 'The package you are attempting to install is missing the package-info.xml that must be in the root package directory.';
 $txt['package_get_error_is_zero'] = 'Although the package was downloaded to the server it appears to be empty. Please check the Packages directory, and the &quot;temp&quot; sub-directory are both writable. If you continue to experience this problem you should try extracting the package on your PC and uploading the extracted files into a subdirectory in your Packages directory and try again. For example, if the package was called shout.tar.gz you should:<br />1) Download the package to your local PC and extract it into files.<br />2) Using an FTP client create a new directory in your &quot;Packages&quot; folder, in this example you may call it "shout".<br />3) Upload all the files from the extracted package to this directory.<br />4) Go back to the package manager browse page and the package will be automatically found by SMF.';
-$txt['package_get_error_packageinfo_corrupt'] = 'SMF was unable to find any valid information within the package-info.xml file included within the Package. There may be an error with the modification, or the package may be corrupt.';
-$txt['package_get_error_is_theme'] = 'You can\'t install a Theme from this section, please use the <a href="{MANAGETHEMEURL}">Themes and Layout</a> management page to upload it';
+$txt['package_get_error_packageinfo_corrupt'] = 'SMF was unable to find any valid information within the package-info.xml file of the package. There may be an error with the modification, or the package may be corrupt.';
+$txt['package_get_error_is_theme'] = 'The package you are trying to install is a theme and not a mod. Please use the <a href="{MANAGETHEMEURL}">Themes and Layout</a> management page to upload it';
 
 $txt['no_membergroup_selected'] = 'No membergroup selected';
 $txt['membergroup_does_not_exist'] = 'The membergroup doesn\'t exist or is invalid.';

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

@@ -285,7 +285,7 @@ $helptxt['cache_cachedir'] = 'This setting This is only for the smf file based c
 $helptxt['enableErrorLogging'] = 'This will log any errors, like a failed login, so you can see what went wrong.';
 $helptxt['enableErrorQueryLogging'] = 'This will include the full query sent to the database in the error log.  Requires error logging to be turned on.<br /><br /><strong>Note:  This will affect the ability to filter the error log by the error message.</strong>';
 $helptxt['allow_disableAnnounce'] = 'This will allow users to opt out of notification of topics you announce by checking the &quot;announce topic&quot; checkbox when posting.';
-$helptxt['disallow_sendBody'] = 'This option removes the option to receive the text of replies and posts in notification emails.<br /><br />Often, members will reply to the notification email, which in most cases means the webmaster receives the reply.';
+$helptxt['disallow_sendBody'] = 'This option removes the option to receive the text of replies, posts and personal messages in notification emails.<br /><br />Often, members will reply to the notification email, which in most cases means the webmaster receives the reply.';
 $helptxt['jquery_source'] = 'This will determine the source used to load the Jquery Library.  Auto will use the CDN first and if not available fall back to the local source.  Local will only use the local source, CDN will only load it from Googles CDN network';
 $helptxt['compactTopicPagesEnable'] = 'This will just show a selection of the number of pages.<br /><em>Example:</em>
 		&quot;3&quot; to display: 1 ... 4 [5] 6 ... 9 <br />

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

@@ -86,4 +86,6 @@ $txt['modlog_ac_restore_posts'] = 'Restored posts from &quot;{subject}&quot; to
 
 $txt['modlog_parameter_guest'] = '<em>Guest</em>';
 
+$txt['modlog_ac_approve_attach'] = 'Approved &quot;{filename}&quot; in &quot;{message}&quot;';
+$txt['modlog_ac_remove_attach'] = 'Removed unapproved &quot;{filename}&quot; in &quot;{message}&quot;';
 ?>

+ 0 - 7
Themes/default/languages/PersonalMessage.english.php

@@ -19,13 +19,6 @@ $txt['delete_message'] = 'Delete Messages';
 $txt['delete_all'] = 'Delete all messages in your PMBOX';
 $txt['delete_all_confirm'] = 'Are you sure you want to delete all messages?';
 $txt['recipient'] = 'Recipient';
-// Don't translate the word "SUBJECT" here, as it is used to format the message - use numeric entities as well.
-$txt['new_pm_subject'] = 'New Personal Message: SUBJECT';
-// Don't translate SENDER or MESSAGE in this language string; they are replaced with the corresponding text - use numeric entities too.
-$txt['pm_email'] = 'You have just been sent a personal message by SENDER on ' . $context['forum_name'] . '.' . "\n\n" . 'IMPORTANT: Remember, this is just a notification. Please do not reply to this email.' . "\n\n" . 'The message they sent you was:' . "\n\n" . 'MESSAGE';
-$txt['pm_multiple'] = '(multiple recipients: \'name1, name2\')';
-// Use numeric entities in the below string.
-$txt['instant_reply'] = 'Reply to this Personal Message here:';
 
 $txt['delete_selected_confirm'] = 'Are you sure you want to delete all selected personal messages?';
 

+ 12 - 155
Themes/default/scripts/fader.js

@@ -4,20 +4,6 @@ function smf_NewsFader(oOptions)
 
 	this.oFaderHandle = document.getElementById(this.opt.sFaderControlId);
 
-	// Fade from... what text color? Default to black.
-	this.oFadeFrom = 'oFadeFrom' in this.opt ? this.opt.oFadeFrom : {
-		r: 0,
-		g: 0,
-		b: 0
-	};
-
-	// To which background color? Default to white.
-	this.oFadeTo = 'oFadeTo' in this.opt ? this.opt.oFadeTo : {
-		r: 255,
-		g: 255,
-		b: 255
-	};
-
 	// Surround each item with... anything special?
 	this.sItemTemplate = 'sItemTemplate' in this.opt ? this.opt.sItemTemplate : '%1$s';
 
@@ -33,66 +19,15 @@ function smf_NewsFader(oOptions)
 	// The current item in smfFadeContent.
 	this.iFadeIndex = -1;
 
-	// Percent of fade (-64 to 510).
-	this.iFadePercent = 510
-
-	// Direction (in or out).
-	this.bFadeSwitch = false;
-
 	// Just make sure the page is loaded before calling the init.
-	setTimeout(this.opt.sSelf + '.init();', 1);
+	var fader = this;
+	$(document).ready(function() {fader.init();});
 }
 
 smf_NewsFader.prototype.init = function init()
 {
 	var oForeEl, oForeColor, oBackEl, oBackColor;
 
-	// Try to find the fore- and background colors.
-	if ('currentStyle' in this.oFaderHandle)
-	{
-		oForeColor = this.oFaderHandle.currentStyle.color.match(/#([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/);
-		this.oFadeFrom = {
-			r: parseInt(oForeColor[1]),
-			g: parseInt(oForeColor[2]),
-			b: parseInt(oForeColor[3])
-		};
-
-		oBackEl = this.oFaderHandle;
-		while (oBackEl.currentStyle.backgroundColor == 'transparent' && 'parentNode' in oBackEl)
-			oBackEl = oBackEl.parentNode;
-
-		oBackColor = oBackEl.currentStyle.backgroundColor.match(/#([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/);
-		this.oFadeTo = {
-			r: eval('0x' + oBackColor[1]),
-			g: eval('0x' + oBackColor[2]),
-			b: eval('0x' + oBackColor[3])
-		};
-	}
-	else if (!('opera' in window) && 'defaultView' in document)
-	{
-		oForeEl = this.oFaderHandle;
-		while (document.defaultView.getComputedStyle(oForeEl, null).getPropertyCSSValue('color') == null && 'parentNode' in oForeEl && 'tagName' in oForeEl.parentNode)
-			oForeEl = oForeEl.parentNode;
-
-		oForeColor = document.defaultView.getComputedStyle(oForeEl, null).getPropertyValue('color').match(/rgb\((\d+), (\d+), (\d+)\)/);
-		this.oFadeFrom = {
-			r: parseInt(oForeColor[1]),
-			g: parseInt(oForeColor[2]),
-			b: parseInt(oForeColor[3])
-		};
-
-		oBackEl = this.oFaderHandle;
-		while (document.defaultView.getComputedStyle(oBackEl, null).getPropertyCSSValue('background-color') == null && 'parentNode' in oBackEl && 'tagName' in oBackEl.parentNode)
-			oBackEl = oBackEl.parentNode;
-
-		oBackColor = document.defaultView.getComputedStyle(oBackEl, null).getPropertyValue('background-color');
-		this.oFadeTo = {
-			r: parseInt(oBackColor[1]),
-			g: parseInt(oBackColor[2]),
-			b: parseInt(oBackColor[3])
-		};
-	}
-
 	// Did we get our fader items on construction, or should we be gathering them instead?
 	if (!this.bReceivedItemsOnConstruction)
 	{
@@ -103,19 +38,10 @@ smf_NewsFader.prototype.init = function init()
 		for (var i = 0, n = oNewsItems.length; i < n; i ++)
 			this.aFaderItems[i] = oNewsItems[i].innerHTML;
 	}
-
-	// The ranges to fade from for R, G, and B. (how far apart they are.)
-	this.oFadeRange = {
-		'r': this.oFadeFrom.r - this.oFadeTo.r,
-		'g': this.oFadeFrom.g - this.oFadeTo.g,
-		'b': this.oFadeFrom.b - this.oFadeTo.b
-	};
-
-	// Divide by 20 because we are doing it 20 times per one ms.
-	this.iFadeDelay /= 20;
+	$('#' + this.opt.sFaderControlId).fadeOut('fast');
 
 	// Start the fader!
-	window.setTimeout(this.opt.sSelf + '.fade();', 20);
+	this.fade();
 }
 
 // Main	fading function... called 50 times every second.
@@ -124,94 +50,25 @@ smf_NewsFader.prototype.fade = function fade()
 	if (this.aFaderItems.length <= 1)
 		return;
 
-	// A fix for Internet Explorer 4: wait until the document is loaded so we can use setInnerHTML().
-	if ('readyState' in document && document.readyState != 'complete')
-	{
-		window.setTimeout(this.opt.sSelf + '.fade();', 20);
-		return;
-	}
-
+	var currentText;
 	// Starting out?  Set up the first item.
 	if (this.iFadeIndex == -1)
 	{
-		setInnerHTML(this.oFaderHandle, this.sItemTemplate.replace('%1$s', this.aFaderItems[0]));
+		currentText = this.sItemTemplate.replace('%1$s', this.aFaderItems[0]);
 		this.iFadeIndex = 1;
-
-		// In Mozilla, text jumps around from this when 1 or 0.5, etc...
-		if ('MozOpacity' in this.oFaderHandle.style)
-			this.oFaderHandle.style.MozOpacity = '0.90';
-		else if ('opacity' in this.oFaderHandle.style)
-			this.oFaderHandle.style.opacity = '0.90';
-		// In Internet Explorer, we have to define this to use it.
-		else if ('filter' in this.oFaderHandle.style)
-			this.oFaderHandle.style.filter = 'alpha(opacity=100)';
 	}
-
-	// Are we already done fading in?  If so, fade out.
-	if (this.iFadePercent >= 510)
-		this.bFadeSwitch = !this.bFadeSwitch;
-
-	// All the way faded out?
-	else if (this.iFadePercent <= -64)
+	else
 	{
-		this.bFadeSwitch = !this.bFadeSwitch;
-
 		// Go to the next item, or first if we're out of items.
-		setInnerHTML(this.oFaderHandle, this.sItemTemplate.replace('%1$s', this.aFaderItems[this.iFadeIndex ++]));
+		currentText = this.sItemTemplate.replace('%1$s', this.aFaderItems[this.iFadeIndex ++]);
 		if (this.iFadeIndex >= this.aFaderItems.length)
 			this.iFadeIndex = 0;
 	}
 
-	// Increment or decrement the fade percentage.
-	if (this.bFadeSwitch)
-		this.iFadePercent -= 255 / this.iFadeDelay * 2;
-	else
-		this.iFadePercent += 255 / this.iFadeDelay * 2;
-
-	// If it's not outside 0 and 256... (otherwise it's just delay time.)
-	if (this.iFadePercent < 256 && this.iFadePercent > 0)
-	{
-		// Easier... also faster...
-		var tempPercent = this.iFadePercent / 255, rounded;
-
-		if ('MozOpacity' in this.oFaderHandle.style)
-		{
-			rounded = Math.round(tempPercent * 100) / 100;
-			this.oFaderHandle.style.MozOpacity = rounded == 1 ? '0.99' : rounded;
-		}
-		else if ('opacity' in this.oFaderHandle.style)
-		{
-			rounded = Math.round(tempPercent * 100) / 100;
-			this.oFaderHandle.style.opacity = rounded == 1 ? '0.99' : rounded;
-		}
-		else
-		{
-			var done = false;
-			if ('alpha' in this.oFaderHandle.filters)
-			{
-				try
-				{
-					this.oFaderHandle.filters.alpha.opacity = Math.round(tempPercent * 100);
-					done = true;
-				}
-				catch (err)
-				{
-				}
-			}
-
-			if (!done)
-			{
-				// Get the new R, G, and B. (it should be bottom + (range of color * percent)...)
-				var r = Math.ceil(this.oFadeTo.r + this.oFadeRange.r * tempPercent);
-				var g = Math.ceil(this.oFadeTo.g + this.oFadeRange.g * tempPercent);
-				var b = Math.ceil(this.oFadeTo.b + this.oFadeRange.b * tempPercent);
-
-				// Set the color in the style, thereby fading it.
-				this.oFaderHandle.style.color = 'rgb(' + r + ', ' + g + ', ' + b + ')';
-			}
-		}
-	}
+	$('#' + this.opt.sFaderControlId).fadeOut('slow', function () {
+		setInnerHTML(this, currentText);
+	}).fadeIn('slow');
 
 	// Keep going.
-	window.setTimeout(this.opt.sSelf + '.fade();', 20);
+	window.setTimeout(this.opt.sSelf + '.fade();', this.iFadeDelay);
 }

+ 162 - 1
Themes/default/scripts/profile.js

@@ -37,4 +37,165 @@ function disableAutoCompleteNow()
 			if (die[j].type == "text" || die[j].type == "password")
 				die[j].setAttribute("autocomplete", "off");
 	}
-}
+}
+
+function calcCharLeft()
+{
+	var oldSignature = "", currentSignature = document.forms.creator.signature.value;
+	var currentChars = 0;
+
+	if (!document.getElementById("signatureLeft"))
+		return;
+
+	if (oldSignature != currentSignature)
+	{
+		oldSignature = currentSignature;
+
+		var currentChars = currentSignature.replace(/\r/, "").length;
+		if (is_opera)
+			currentChars = currentSignature.replace(/\r/g, "").length;
+
+		
+		if (currentChars > maxLength)
+			document.getElementById("signatureLeft").className = "error";
+		else
+			document.getElementById("signatureLeft").className = "";
+		
+		if (currentChars > maxLength && !$("#profile_error").is(":visible"))
+			ajax_getSignaturePreview(false);
+		else if (currentChars <= maxLength && $("#profile_error").is(":visible"))
+		{
+			$("#profile_error").css({display:"none"});
+			$("#profile_error").html('');
+		}
+	}
+
+	setInnerHTML(document.getElementById("signatureLeft"), maxLength - currentChars);
+}
+
+function ajax_getSignaturePreview (showPreview)
+{
+	showPreview = (typeof showPreview == 'undefined') ? false : showPreview;
+	$.ajax({
+		type: "POST",
+		url: smf_scripturl + "?action=xmlhttp;sa=previews;xml",
+		data: {item: "sig_preview", signature: $("#signature").val(), user: $('input[name="u"]').attr("value")},
+		context: document.body,
+		success: function(request){
+			if (showPreview)
+			{
+				var signatures = new Array("current", "preview");
+				for (var i = 0; i < signatures.length; i++)
+				{
+					$("#" + signatures[i] + "_signature").css({display:""});
+					$("#" + signatures[i] + "_signature_display").css({display:""}).html($(request).find('[type="' + signatures[i] + '"]').text() + '<hr />');
+				}
+			}
+
+			if ($(request).find("error").text() != '')
+			{
+				if (!$("#profile_error").is(":visible"))
+					$("#profile_error").css({display: "", position: "fixed", top: 0, left: 0, width: "100%"});
+				var errors = $(request).find('[type="error"]');
+				var errors_html = '<span>' + $(request).find('[type="errors_occurred"]').text() + '</span><ul class="reset">';
+
+				for (var i = 0; i < errors.length; i++)
+					errors_html += '<li>' + $(errors).text() + '</li>';
+
+				errors_html += '</ul>';
+				$(document).find("#profile_error").html(errors_html);
+			}
+			else
+			{
+				$("#profile_error").css({display:"none"});
+				$("#profile_error").html('');
+			}
+		return false;
+		},
+	});
+	return false;
+}
+
+function changeSel(selected)
+{
+	if (cat.selectedIndex == -1)
+		return;
+
+	if (cat.options[cat.selectedIndex].value.indexOf("/") > 0)
+	{
+		var i;
+		var count = 0;
+
+		file.style.display = "inline";
+		file.disabled = false;
+
+		for (i = file.length; i >= 0; i = i - 1)
+			file.options[i] = null;
+
+		for (i = 0; i < files.length; i++)
+			if (files[i].indexOf(cat.options[cat.selectedIndex].value) == 0)
+			{
+				var filename = files[i].substr(files[i].indexOf("/") + 1);
+				var showFilename = filename.substr(0, filename.lastIndexOf("."));
+				showFilename = showFilename.replace(/[_]/g, " ");
+
+				file.options[count] = new Option(showFilename, files[i]);
+
+				if (filename == selected)
+				{
+					if (file.options.defaultSelected)
+						file.options[count].defaultSelected = true;
+					else
+						file.options[count].selected = true;
+				}
+
+				count++;
+			}
+
+		if (file.selectedIndex == -1 && file.options[0])
+			file.options[0].selected = true;
+
+		showAvatar();
+	}
+	else
+	{
+		file.style.display = "none";
+		file.disabled = true;
+		document.getElementById("avatar").src = avatardir + cat.options[cat.selectedIndex].value;
+		document.getElementById("avatar").style.width = "";
+		document.getElementById("avatar").style.height = "";
+	}
+}
+
+function showAvatar()
+{
+	if (file.selectedIndex == -1)
+		return;
+
+	document.getElementById("avatar").src = avatardir + file.options[file.selectedIndex].value;
+	document.getElementById("avatar").alt = file.options[file.selectedIndex].text;
+	document.getElementById("avatar").alt += file.options[file.selectedIndex].text == size ? "!" : "";
+	document.getElementById("avatar").style.width = "";
+	document.getElementById("avatar").style.height = "";
+}
+
+function previewExternalAvatar(src)
+{
+	if (!document.getElementById("avatar"))
+		return;
+
+	var tempImage = new Image();
+
+	tempImage.src = src;
+	if (maxWidth != 0 && tempImage.width > maxWidth)
+	{
+		document.getElementById("avatar").style.height = parseInt((maxWidth * tempImage.height) / tempImage.width) + "px";
+		document.getElementById("avatar").style.width = maxWidth + "px";
+	}
+	else if (maxHeight != 0 && tempImage.height > maxHeight)
+	{
+		document.getElementById("avatar").style.width = parseInt((maxHeight * tempImage.width) / tempImage.height) + "px";
+		document.getElementById("avatar").style.height = maxHeight + "px";
+	}
+	document.getElementById("avatar").src = src;
+}

+ 0 - 153
Themes/default/scripts/script.js

@@ -1563,159 +1563,6 @@ function smfSetLatestPackages()
 	tempOldOnload();
 }
 
-function calcCharLeft()
-{
-	var oldSignature = "", currentSignature = document.forms.creator.signature.value;
-	var currentChars = 0;
-
-	if (!document.getElementById("signatureLeft"))
-		return;
-
-	if (oldSignature != currentSignature)
-	{
-		oldSignature = currentSignature;
-
-		var currentChars = currentSignature.replace(/\r/, "").length;
-		if (is_opera)
-			currentChars = currentSignature.replace(/\r/g, "").length;
-
-		ajax_getSignaturePreview(false);
-		if (currentChars > maxLength)
-			document.getElementById("signatureLeft").className = "error";
-		else
-			document.getElementById("signatureLeft").className = "";
-	}
-
-	setInnerHTML(document.getElementById("signatureLeft"), maxLength - currentChars);
-}
-
-function ajax_getSignaturePreview (showPreview)
-{
-	showPreview = (typeof showPreview == 'undefined') ? false : showPreview;
-	$.ajax({
-		type: "POST",
-		url: smf_scripturl + "?action=xmlhttp;sa=previews;xml",
-		data: {item: "sig_preview", signature: $("#signature").val(), user: $('input[name="u"]').attr("value")},
-		context: document.body,
-		success: function(request){
-			if (showPreview)
-			{
-				var signatures = new Array("current", "preview");
-				for (var i = 0; i < signatures.length; i++)
-				{
-					$("#" + signatures[i] + "_signature").css({display:""});
-					$("#" + signatures[i] + "_signature_display").css({display:""}).html($(request).find('[type="' + signatures[i] + '"]').text() + '<hr />');
-				}
-			}
-
-			if ($(request).find("error").text() != '')
-			{
-				if (!$("#profile_error").is(":visible"))
-					$("#profile_error").css({display: "", position: "fixed", top: 0, left: 0, width: "100%"});
-				var errors = $(request).find('[type="error"]');
-				var errors_html = '<span>' + $(request).find('[type="errors_occurred"]').text() + '</span><ul class="reset">';
-
-				for (var i = 0; i < errors.length; i++)
-					errors_html += '<li>' + $(errors).text() + '</li>';
-
-				errors_html += '</ul>';
-				$(document).find("#profile_error").html(errors_html);
-			}
-			else
-			{
-				$("#profile_error").css({display:"none"});
-				$("#profile_error").html('');
-			}
-		return false;
-		},
-	});
-	return false;
-}
-
-function changeSel(selected)
-{
-	if (cat.selectedIndex == -1)
-		return;
-
-	if (cat.options[cat.selectedIndex].value.indexOf("/") > 0)
-	{
-		var i;
-		var count = 0;
-
-		file.style.display = "inline";
-		file.disabled = false;
-
-		for (i = file.length; i >= 0; i = i - 1)
-			file.options[i] = null;
-
-		for (i = 0; i < files.length; i++)
-			if (files[i].indexOf(cat.options[cat.selectedIndex].value) == 0)
-			{
-				var filename = files[i].substr(files[i].indexOf("/") + 1);
-				var showFilename = filename.substr(0, filename.lastIndexOf("."));
-				showFilename = showFilename.replace(/[_]/g, " ");
-
-				file.options[count] = new Option(showFilename, files[i]);
-
-				if (filename == selected)
-				{
-					if (file.options.defaultSelected)
-						file.options[count].defaultSelected = true;
-					else
-						file.options[count].selected = true;
-				}
-
-				count++;
-			}
-
-		if (file.selectedIndex == -1 && file.options[0])
-			file.options[0].selected = true;
-
-		showAvatar();
-	}
-	else
-	{
-		file.style.display = "none";
-		file.disabled = true;
-		document.getElementById("avatar").src = avatardir + cat.options[cat.selectedIndex].value;
-		document.getElementById("avatar").style.width = "";
-		document.getElementById("avatar").style.height = "";
-	}
-}
-
-function showAvatar()
-{
-	if (file.selectedIndex == -1)
-		return;
-
-	document.getElementById("avatar").src = avatardir + file.options[file.selectedIndex].value;
-	document.getElementById("avatar").alt = file.options[file.selectedIndex].text;
-	document.getElementById("avatar").alt += file.options[file.selectedIndex].text == size ? "!" : "";
-	document.getElementById("avatar").style.width = "";
-	document.getElementById("avatar").style.height = "";
-}
-
-function previewExternalAvatar(src)
-{
-	if (!document.getElementById("avatar"))
-		return;
-
-	var tempImage = new Image();
-
-	tempImage.src = src;
-	if (maxWidth != 0 && tempImage.width > maxWidth)
-	{
-		document.getElementById("avatar").style.height = parseInt((maxWidth * tempImage.height) / tempImage.width) + "px";
-		document.getElementById("avatar").style.width = maxWidth + "px";
-	}
-	else if (maxHeight != 0 && tempImage.height > maxHeight)
-	{
-		document.getElementById("avatar").style.width = parseInt((maxHeight * tempImage.width) / tempImage.height) + "px";
-		document.getElementById("avatar").style.height = maxHeight + "px";
-	}
-	document.getElementById("avatar").src = src;
-}
-
 function updateAuthMethod()
 {
 	// What authentication method is being used?

+ 1 - 1
other/install.php

@@ -911,7 +911,7 @@ function ForumSettings()
 
 	// Check if the database sessions will even work.
 	$incontext['test_dbsession'] = ini_get('session.auto_start') != 1;
-	$incontext['utf8_should_work'] = stripos(PHP_OS, 'win') !== false;
+	$incontext['utf8_should_work'] = stripos(PHP_OS, 'win') === false;
 	$incontext['utf8_default'] = $databases[$db_type]['utf8_default'];
 	$incontext['utf8_required'] = $databases[$db_type]['utf8_required'];
 

+ 7 - 4
other/install_2-1_mysql.sql

@@ -841,7 +841,7 @@ CREATE TABLE {$db_prefix}log_errors (
   ip char(16) NOT NULL default '                ',
   url text NOT NULL,
   message text NOT NULL,
-  session char(32) NOT NULL default '                                ',
+  session char(64) NOT NULL default '                                                                ',
   error_type char(15) NOT NULL default 'general',
   file varchar(255) NOT NULL default '',
   line mediumint(8) unsigned NOT NULL default '0',
@@ -929,7 +929,7 @@ CREATE TABLE {$db_prefix}log_notify (
 #
 
 CREATE TABLE {$db_prefix}log_online (
-  session varchar(32) NOT NULL default '',
+  session varchar(64) NOT NULL default '',
   log_time int(10) NOT NULL default '0',
   id_member mediumint(8) unsigned NOT NULL default '0',
   id_spider smallint(5) unsigned NOT NULL default '0',
@@ -1471,6 +1471,7 @@ VALUES (-1, 'search_posts'),
 	(0, 'profile_server_avatar'),
 	(0, 'profile_upload_avatar'),
 	(0, 'profile_remote_avatar'),
+	(0, 'send_email_to_members'),
 	(0, 'karma_edit'),
 	(2, 'view_mlist'),
 	(2, 'search_posts'),
@@ -1487,6 +1488,7 @@ VALUES (-1, 'search_posts'),
 	(2, 'profile_server_avatar'),
 	(2, 'profile_upload_avatar'),
 	(2, 'profile_remote_avatar'),
+	(2, 'send_email_to_members'),
 	(2, 'profile_title_own'),
 	(2, 'calendar_post'),
 	(2, 'calendar_edit_any'),
@@ -1611,7 +1613,8 @@ VALUES
 	(7, 0, {$sched_task_offset}, 1, 'd', 0, 'fetchSMfiles'),
 	(8, 0, 0, 1, 'd', 1, 'birthdayemails'),
 	(9, 0, 0, 1, 'w', 0, 'weekly_maintenance'),
-	(10, 0, 120, 1, 'd', 1, 'paid_subscriptions');
+	(10, 0, 120, 1, 'd', 1, 'paid_subscriptions'),
+	(11, 0, 120, 1, 'd', 1, 'remove_temp_attachments');
 
 # --------------------------------------------------------
 
@@ -1810,7 +1813,7 @@ VALUES ('smfVersion', '{$smf_version}'),
 #
 
 CREATE TABLE {$db_prefix}sessions (
-  session_id char(32) NOT NULL,
+  session_id char(64) NOT NULL,
   last_update int(10) unsigned NOT NULL,
   data text NOT NULL,
   PRIMARY KEY (session_id)

+ 33 - 30
other/install_2-1_postgresql.sql

@@ -750,36 +750,36 @@ CREATE INDEX {$db_prefix}calendar_holidays_event_date ON {$db_prefix}calendar_ho
 # Dumping data for table `calendar_holidays`
 #
 
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('New Year\'s', '0004-01-01');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('New Year''s', '0004-01-01');
 INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Christmas', '0004-12-25');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Valentine\'s Day', '0004-02-14');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('St. Patrick\'s Day', '0004-03-17');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Valentine''s Day', '0004-02-14');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('St. Patrick''s Day', '0004-03-17');
 INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('April Fools', '0004-04-01');
 INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Earth Day', '0004-04-22');
 INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('United Nations Day', '0004-10-24');
 INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Halloween', '0004-10-31');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother\'s Day', '2010-05-09');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother\'s Day', '2011-05-08');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother\'s Day', '2012-05-13');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother\'s Day', '2013-05-12');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother\'s Day', '2014-05-11');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother\'s Day', '2015-05-10');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother\'s Day', '2016-05-08');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother\'s Day', '2017-05-14');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother\'s Day', '2018-05-13');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother\'s Day', '2019-05-12');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother\'s Day', '2020-05-10');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father\'s Day', '2010-06-20');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father\'s Day', '2011-06-19');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father\'s Day', '2012-06-17');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father\'s Day', '2013-06-16');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father\'s Day', '2014-06-15');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father\'s Day', '2015-06-21');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father\'s Day', '2016-06-19');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father\'s Day', '2017-06-18');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father\'s Day', '2018-06-17');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father\'s Day', '2019-06-16');
-INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father\'s Day', '2020-06-21');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother''s Day', '2010-05-09');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother''s Day', '2011-05-08');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother''s Day', '2012-05-13');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother''s Day', '2013-05-12');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother''s Day', '2014-05-11');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother''s Day', '2015-05-10');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother''s Day', '2016-05-08');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother''s Day', '2017-05-14');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother''s Day', '2018-05-13');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother''s Day', '2019-05-12');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Mother''s Day', '2020-05-10');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father''s Day', '2010-06-20');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father''s Day', '2011-06-19');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father''s Day', '2012-06-17');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father''s Day', '2013-06-16');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father''s Day', '2014-06-15');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father''s Day', '2015-06-21');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father''s Day', '2016-06-19');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father''s Day', '2017-06-18');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father''s Day', '2018-06-17');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father''s Day', '2019-06-16');
+INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Father''s Day', '2020-06-21');
 INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Summer Solstice', '2010-06-21');
 INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Summer Solstice', '2011-06-21');
 INSERT INTO {$db_prefix}calendar_holidays (title, event_date) VALUES ('Summer Solstice', '2012-06-20');
@@ -1099,7 +1099,7 @@ CREATE TABLE {$db_prefix}log_errors (
   ip varchar(16) NOT NULL default '',
   url text NOT NULL,
   message text NOT NULL,
-  session char(32) NOT NULL default '                                ',
+  session char(64) NOT NULL default '                                                                ',
   error_type varchar(15) NOT NULL default 'general',
   file varchar(255) NOT NULL,
   line int NOT NULL default '0',
@@ -1219,7 +1219,7 @@ CREATE INDEX {$db_prefix}log_notify_id_topic ON {$db_prefix}log_notify (id_topic
 #
 
 CREATE TABLE {$db_prefix}log_online (
-  session varchar(32) NOT NULL default '',
+  session varchar(64) NOT NULL default '',
   log_time int NOT NULL default '0',
   id_member int NOT NULL default '0',
   id_spider smallint NOT NULL default '0',
@@ -1921,6 +1921,7 @@ INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_r
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_server_avatar');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_upload_avatar');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_remote_avatar');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'send_email_to_members');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'karma_edit');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'view_mlist');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'search_posts');
@@ -1937,6 +1938,7 @@ INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_r
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_server_avatar');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_upload_avatar');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_remote_avatar');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'send_email_to_members');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_title_own');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'calendar_post');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'calendar_edit_any');
@@ -2103,6 +2105,7 @@ INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_r
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (8, 0, 0, 1, 'd', 1, 'birthdayemails');
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (9, 0, 0, 1, 'w', 0, 'weekly_maintenance');
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (10, 0, 120, 1, 'd', 1, 'paid_subscriptions');
+INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (11, 0, 120, 1, 'd', 1, 'remove_temp_attachments');
 
 # --------------------------------------------------------
 
@@ -2299,7 +2302,7 @@ INSERT INTO {$db_prefix}settings (variable, value) VALUES ('avatar_paranoid', '0
 #
 
 CREATE TABLE {$db_prefix}sessions (
-  session_id char(32) NOT NULL,
+  session_id char(64) NOT NULL,
   last_update int NOT NULL,
   data text NOT NULL,
   PRIMARY KEY (session_id)
@@ -2343,9 +2346,9 @@ INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidd
 INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidden) VALUES (':P', 'tongue.gif', '{$default_tongue_smiley}', 10, 0);
 INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidden) VALUES (':-[', 'embarrassed.gif', '{$default_embarrassed_smiley}', 11, 0);
 INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidden) VALUES (':-X', 'lipsrsealed.gif', '{$default_lips_sealed_smiley}', 12, 0);
-INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidden) VALUES (':-\\', 'undecided.gif', '{$default_undecided_smiley}', 13, 0);
+INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidden) VALUES (':-\', 'undecided.gif', '{$default_undecided_smiley}', 13, 0);
 INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidden) VALUES (':-*', 'kiss.gif', '{$default_kiss_smiley}', 14, 0);
-INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidden) VALUES (':\'(', 'cry.gif', '{$default_cry_smiley}', 15, 0);
+INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidden) VALUES (':''(', 'cry.gif', '{$default_cry_smiley}', 15, 0);
 INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidden) VALUES ('>:D', 'evil.gif', '{$default_evil_smiley}', 16, 1);
 INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidden) VALUES ('^-^', 'azn.gif', '{$default_azn_smiley}', 17, 1);
 INSERT INTO {$db_prefix}smileys	(code, filename, description, smiley_order, hidden) VALUES ('O0', 'afro.gif', '{$default_afro_smiley}', 18, 1);

+ 6 - 3
other/install_2-1_sqlite.sql

@@ -880,7 +880,7 @@ CREATE TABLE {$db_prefix}log_errors (
   ip char(16) NOT NULL default '                ',
   url text NOT NULL,
   message text NOT NULL,
-  session char(32) NOT NULL default '                                ',
+  session char(64) NOT NULL default '                                                                ',
   error_type char(15) NOT NULL default 'general',
   file varchar(255) NOT NULL,
   line int NOT NULL default '0'
@@ -985,7 +985,7 @@ CREATE INDEX {$db_prefix}log_notify_id_topic ON {$db_prefix}log_notify (id_topic
 #
 
 CREATE TABLE {$db_prefix}log_online (
-  session varchar(32) NOT NULL default '',
+  session varchar(64) NOT NULL default '',
   log_time int(10) NOT NULL default '0',
   id_member int NOT NULL default '0',
   id_spider smallint NOT NULL default '0',
@@ -1597,6 +1597,7 @@ INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_r
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_server_avatar');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_upload_avatar');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_remote_avatar');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'send_email_to_members');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'karma_edit');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'view_mlist');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'search_posts');
@@ -1613,6 +1614,7 @@ INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_r
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_server_avatar');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_upload_avatar');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_remote_avatar');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'send_email_to_members');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_title_own');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'calendar_post');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'calendar_edit_any');
@@ -1754,6 +1756,7 @@ INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_r
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (8, 0, 0, 1, 'd', 1, 'birthdayemails');
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (9, 0, 0, 1, 'w', 0, 'weekly_maintenance');
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (10, 0, 120, 1, 'd', 1, 'paid_subscriptions');
+INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (11, 0, 120, 1, 'd', 1, 'remove_temp_attachments');
 COMMIT;
 
 # --------------------------------------------------------
@@ -1957,7 +1960,7 @@ COMMIT;
 #
 
 CREATE TABLE {$db_prefix}sessions (
-  session_id char(32) NOT NULL,
+  session_id char(64) NOT NULL,
   last_update int NOT NULL,
   data text NOT NULL,
   PRIMARY KEY (session_id)

+ 33 - 9
other/upgrade_2-1_mysql.sql

@@ -112,14 +112,14 @@ ADD COLUMN ip_high8 smallint(255) unsigned NOT NULL DEFAULT '0';
 
 ---# Changing existing columns to ban items...
 ALTER TABLE {$db_prefix}ban_items
-CHANGE ip_low1 ip_low1 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high1 ip_high1 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_low2 ip_low2 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high2 ip_high2 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_low3 ip_low3 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high3 ip_high3 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_low4 ip_low4 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high4 ip_high4 tinyint(3) unsigned NOT NULL DEFAULT '0';
+CHANGE ip_low1 ip_low1 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high1 ip_high1 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_low2 ip_low2 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high2 ip_high2 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_low3 ip_low3 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high3 ip_high3 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_low4 ip_low4 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high4 ip_high4 smallint(255) unsigned NOT NULL DEFAULT '0';
 ---#
 
 /******************************************************************************/
@@ -128,4 +128,28 @@ CHANGE ip_high4 ip_high4 tinyint(3) unsigned NOT NULL DEFAULT '0';
 ---# Adding new columns to log_packages ..
 ALTER TABLE {$db_prefix}log_packages
 ADD COLUMN credits varchar(255) NOT NULL DEFAULT '';
----#
+---#
+
+/******************************************************************************/
+--- Adding more space for session ids
+/******************************************************************************/
+---# Altering the session_id columns...
+ALTER TABLE {$db_prefix}log_online
+CHANGE `session` varchar(64) NOT NULL DEFAULT '';
+
+ALTER TABLE {$db_prefix}log_errors
+CHANGE `session` char(64) NOT NULL default '                                                                ';
+
+ALTER TABLE {$db_prefix}sessions
+CHANGE `session_id` char(64) NOT NULL default '';
+---#
+
+/******************************************************************************/
+--- Adding new scheduled tasts
+/******************************************************************************/
+---# Adding new Scheduled Task...
+INSERT INTO {$db_prefix}scheduled_tasks
+	(next_time, time_offset, time_regularity, time_unit, disabled, task)
+VALUES
+	(0, 120, 1, 'd', 0, 'remove_temp_attachments');
+---#

+ 33 - 9
other/upgrade_2-1_postgresql.sql

@@ -116,14 +116,14 @@ ADD COLUMN ip_high8 smallint(255) unsigned NOT NULL DEFAULT '0';
 
 ---# Changing existing columns to ban items...
 ALTER TABLE {$db_prefix}ban_items
-CHANGE ip_low1 ip_low1 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high1 ip_high1 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_low2 ip_low2 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high2 ip_high2 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_low3 ip_low3 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high3 ip_high3 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_low4 ip_low4 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high4 ip_high4 tinyint(3) unsigned NOT NULL DEFAULT '0';
+CHANGE ip_low1 ip_low1 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high1 ip_high1 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_low2 ip_low2 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high2 ip_high2 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_low3 ip_low3 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high3 ip_high3 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_low4 ip_low4 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high4 ip_high4 smallint(255) unsigned NOT NULL DEFAULT '0';
 ---#
 
 /******************************************************************************/
@@ -132,4 +132,28 @@ CHANGE ip_high4 ip_high4 tinyint(3) unsigned NOT NULL DEFAULT '0';
 ---# Adding new columns to log_packages ..
 ALTER TABLE {$db_prefix}log_packages
 ADD COLUMN credits varchar(255) NOT NULL DEFAULT '';
----#
+---#
+
+/******************************************************************************/
+--- Adding more space for session ids
+/******************************************************************************/
+---# Altering the session_id columns...
+ALTER TABLE {$db_prefix}log_online
+CHANGE `session` varchar(64) NOT NULL DEFAULT '';
+
+ALTER TABLE {$db_prefix}log_errors
+CHANGE `session` char(64) NOT NULL default '                                                                ';
+
+ALTER TABLE {$db_prefix}sessions
+CHANGE `session_id` char(64) NOT NULL default '';
+---#
+
+/******************************************************************************/
+--- Adding new scheduled tasts
+/******************************************************************************/
+---# Adding new Scheduled Task...
+INSERT INTO {$db_prefix}scheduled_tasks
+	(next_time, time_offset, time_regularity, time_unit, disabled, task)
+VALUES
+	(0, 120, 1, 'd', 0, 'remove_temp_attachments');
+---#

+ 33 - 9
other/upgrade_2-1_sqlite.sql

@@ -112,14 +112,14 @@ ADD COLUMN ip_high8 smallint(255) unsigned NOT NULL DEFAULT '0';
 
 ---# Changing existing columns to ban items...
 ALTER TABLE {$db_prefix}ban_items
-CHANGE ip_low1 ip_low1 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high1 ip_high1 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_low2 ip_low2 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high2 ip_high2 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_low3 ip_low3 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high3 ip_high3 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_low4 ip_low4 tinyint(3) unsigned NOT NULL DEFAULT '0',
-CHANGE ip_high4 ip_high4 tinyint(3) unsigned NOT NULL DEFAULT '0';
+CHANGE ip_low1 ip_low1 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high1 ip_high1 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_low2 ip_low2 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high2 ip_high2 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_low3 ip_low3 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high3 ip_high3 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_low4 ip_low4 smallint(255) unsigned NOT NULL DEFAULT '0',
+CHANGE ip_high4 ip_high4 smallint(255) unsigned NOT NULL DEFAULT '0';
 ---#
 
 /******************************************************************************/
@@ -128,4 +128,28 @@ CHANGE ip_high4 ip_high4 tinyint(3) unsigned NOT NULL DEFAULT '0';
 ---# Adding new columns to log_packages ..
 ALTER TABLE {$db_prefix}log_packages
 ADD COLUMN credits varchar(255) NOT NULL DEFAULT '';
----#
+---#
+
+/******************************************************************************/
+--- Adding more space for session ids
+/******************************************************************************/
+---# Altering the session_id columns...
+ALTER TABLE {$db_prefix}log_online
+CHANGE `session` varchar(64) NOT NULL DEFAULT '';
+
+ALTER TABLE {$db_prefix}log_errors
+CHANGE `session` char(64) NOT NULL default '                                                                ';
+
+ALTER TABLE {$db_prefix}sessions
+CHANGE `session_id` char(64) NOT NULL default '';
+---#
+
+/******************************************************************************/
+--- Adding new scheduled tasts
+/******************************************************************************/
+---# Adding new Scheduled Task...
+INSERT INTO {$db_prefix}scheduled_tasks
+	(next_time, time_offset, time_regularity, time_unit, disabled, task)
+VALUES
+	(0, 120, 1, 'd', 0, 'remove_temp_attachments');
+---#