Passed
Pull Request — release-2.1 (#5074)
by John
05:52
created

Post.php ➔ AnnouncementSend()   F

Complexity

Conditions 21
Paths > 20000

Size

Total Lines 132

Duplication

Lines 2
Ratio 1.52 %

Importance

Changes 0
Metric Value
cc 21
nc 30720
nop 0
dl 2
loc 132
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * The job of this file is to handle everything related to posting replies,
5
 * new topics, quotes, and modifications to existing posts.  It also handles
6
 * quoting posts by way of javascript.
7
 * Simple Machines Forum (SMF)
8
 *
9
 * @package SMF
10
 * @author Simple Machines http://www.simplemachines.org
11
 * @copyright 2018 Simple Machines and individual contributors
12
 * @license http://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1 Beta 4
15
 */
16
17
if (!defined('SMF'))
18
	die('No direct access...');
19
20
/**
21
 * Handles showing the post screen, loading the post to be modified, and loading any post quoted.
22
 *
23
 * - additionally handles previews of posts.
24
 * - @uses the Post template and language file, main sub template.
25
 * - requires different permissions depending on the actions, but most notably post_new, post_reply_own, and post_reply_any.
26
 * - shows options for the editing and posting of calendar events and attachments, as well as the posting of polls.
27
 * - accessed from ?action=post.
28
 *
29
 *  @param array $post_errors Holds any errors found while tyring to post
30
 */
31
function Post($post_errors = array())
32
{
33
	global $txt, $scripturl, $topic, $modSettings, $board;
34
	global $user_info, $context, $settings;
35
	global $sourcedir, $smcFunc, $language;
36
37
	loadLanguage('Post');
38
	if (!empty($modSettings['drafts_post_enabled']))
39
		loadLanguage('Drafts');
40
41
	// You can't reply with a poll... hacker.
42
	if (isset($_REQUEST['poll']) && !empty($topic) && !isset($_REQUEST['msg']))
43
		unset($_REQUEST['poll']);
44
45
	// Posting an event?
46
	$context['make_event'] = isset($_REQUEST['calendar']);
47
	$context['robot_no_index'] = true;
48
49
	call_integration_hook('integrate_post_start');
50
51
	// Get notification preferences for later
52
	require_once($sourcedir . '/Subs-Notify.php');
53
	// use $temp to get around "Only variables should be passed by reference"
54
	$temp = getNotifyPrefs($user_info['id']);
55
	$context['notify_prefs'] = (array) array_pop($temp);
56
	$context['auto_notify'] = !empty($context['notify_prefs']['msg_auto_notify']);
57
58
	// Not in a board? Fine, but we'll make them pick one eventually.
59
	if (empty($board) || $context['make_event'])
60
	{
61
		// Get ids of all the boards they can post in.
62
		$post_permissions = array('post_new');
63
		if ($modSettings['postmod_active'])
64
			$post_permissions[] = 'post_unapproved_topics';
65
66
		$boards = boardsAllowedTo($post_permissions);
67
		if (empty($boards))
68
			fatal_lang_error('cannot_post_new', false);
69
70
		// Get a list of boards for the select menu
71
		require_once($sourcedir . '/Subs-MessageIndex.php');
72
		$boardListOptions = array(
73
			'included_boards' => in_array(0, $boards) ? null : $boards,
74
			'not_redirection' => true,
75
			'use_permissions' => true,
76
			'selected_board' => !empty($board) ? $board : ($context['make_event'] && !empty($modSettings['cal_defaultboard']) ? $modSettings['cal_defaultboard'] : $boards[0]),
77
		);
78
		$board_list = getBoardList($boardListOptions);
79
	}
80
	// Let's keep things simple for ourselves below
81
	else
82
		$boards = array($board);
83
84
	require_once($sourcedir . '/Subs-Post.php');
85
86
	if (isset($_REQUEST['xml']))
87
	{
88
		$context['sub_template'] = 'post';
89
90
		// Just in case of an earlier error...
91
		$context['preview_message'] = '';
92
		$context['preview_subject'] = '';
93
	}
94
95
	// No message is complete without a topic.
96
	if (empty($topic) && !empty($_REQUEST['msg']))
97
	{
98
		$request = $smcFunc['db_query']('', '
99
			SELECT id_topic
100
			FROM {db_prefix}messages
101
			WHERE id_msg = {int:msg}',
102
			array(
103
				'msg' => (int) $_REQUEST['msg'],
104
		));
105
		if ($smcFunc['db_num_rows']($request) != 1)
106
			unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
107
		else
108
			list ($topic) = $smcFunc['db_fetch_row']($request);
109
		$smcFunc['db_free_result']($request);
110
	}
111
112
	// Check if it's locked. It isn't locked if no topic is specified.
113
	if (!empty($topic))
114
	{
115
		$request = $smcFunc['db_query']('', '
116
			SELECT
117
				t.locked, t.approved, COALESCE(ln.id_topic, 0) AS notify, t.is_sticky, t.id_poll, t.id_last_msg, mf.id_member,
118
				t.id_first_msg, mf.subject, ml.modified_reason,
119
				CASE WHEN ml.poster_time > ml.modified_time THEN ml.poster_time ELSE ml.modified_time END AS last_post_time
120
			FROM {db_prefix}topics AS t
121
				LEFT JOIN {db_prefix}log_notify AS ln ON (ln.id_topic = t.id_topic AND ln.id_member = {int:current_member})
122
				LEFT JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)
123
				LEFT JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
124
			WHERE t.id_topic = {int:current_topic}
125
			LIMIT 1',
126
			array(
127
				'current_member' => $user_info['id'],
128
				'current_topic' => $topic,
129
			)
130
		);
131
		list ($locked, $topic_approved, $context['notify'], $sticky, $pollID, $context['topic_last_message'], $id_member_poster, $id_first_msg, $first_subject, $editReason, $lastPostTime) = $smcFunc['db_fetch_row']($request);
132
		$smcFunc['db_free_result']($request);
133
134
		// If this topic already has a poll, they sure can't add another.
135
		if (isset($_REQUEST['poll']) && $pollID > 0)
136
			unset($_REQUEST['poll']);
137
138
		if (empty($_REQUEST['msg']))
139
		{
140
			if ($user_info['is_guest'] && !allowedTo('post_reply_any') && (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_replies_any')))
141
				is_not_guest();
142
143
			// By default the reply will be approved...
144
			$context['becomes_approved'] = true;
145
			if ($id_member_poster != $user_info['id'] || $user_info['is_guest'])
146
			{
147
				if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any'))
148
					$context['becomes_approved'] = false;
149
				else
150
					isAllowedTo('post_reply_any');
151
			}
152
			elseif (!allowedTo('post_reply_any'))
153
			{
154
				if ($modSettings['postmod_active'] && ((allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) || allowedTo('post_unapproved_replies_any')))
155
					$context['becomes_approved'] = false;
156
				else
157
					isAllowedTo('post_reply_own');
158
			}
159
		}
160
		else
161
			$context['becomes_approved'] = true;
162
163
		$context['can_lock'] = allowedTo('lock_any') || ($user_info['id'] == $id_member_poster && allowedTo('lock_own'));
164
		$context['can_sticky'] = allowedTo('make_sticky');
165
		$context['can_move'] = allowedTo('move_any');
166
		// You can only announce topics that will get approved...
167
		$context['can_announce'] = allowedTo('announce_topic') && $context['becomes_approved'];
168
		$context['show_approval'] = !allowedTo('approve_posts') ? 0 : ($context['becomes_approved'] && !empty($topic_approved) ? 2 : 1);
169
170
		// We don't always want the request vars to override what's in the db...
171
		$context['already_locked'] = $locked;
172
		$context['already_sticky'] = $sticky;
173
		$context['sticky'] = isset($_REQUEST['sticky']) ? !empty($_REQUEST['sticky']) : $sticky;
174
175
		// Check whether this is a really old post being bumped...
176
		if (!empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky) && !isset($_REQUEST['subject']))
177
			$post_errors[] = array('old_topic', array($modSettings['oldTopicDays']));
178
	}
179
	else
180
	{
181
		// @todo Should use JavaScript to hide and show the warning based on the selection in the board select menu
182
		$context['becomes_approved'] = true;
183
		if ($modSettings['postmod_active'] && !allowedTo('post_new', $boards, true) && allowedTo('post_unapproved_topics', $boards, true))
184
			$context['becomes_approved'] = false;
185
		else
186
			isAllowedTo('post_new', $boards, true);
187
188
		$locked = 0;
189
		$context['already_locked'] = 0;
190
		$context['already_sticky'] = 0;
191
		$context['sticky'] = !empty($_REQUEST['sticky']);
192
193
		// What options should we show?
194
		$context['can_lock'] = allowedTo(array('lock_any', 'lock_own'), $boards, true);
195
		$context['can_sticky'] = allowedTo('make_sticky', $boards, true);
196
		$context['can_move'] = allowedTo('move_any', $boards, true);
197
		$context['can_announce'] = allowedTo('announce_topic', $boards, true) && $context['becomes_approved'];
198
		$context['show_approval'] = !allowedTo('approve_posts', $boards, true) ? 0 : ($context['becomes_approved'] ? 2 : 1);
199
	}
200
201
	$context['notify'] = !empty($context['notify']);
202
203
	$context['can_notify'] = !$context['user']['is_guest'];
204
	$context['move'] = !empty($_REQUEST['move']);
205
	$context['announce'] = !empty($_REQUEST['announce']);
206
	$context['locked'] = !empty($locked) || !empty($_REQUEST['lock']);
207
	$context['can_quote'] = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC']));
208
209
	// An array to hold all the attachments for this topic.
210
	$context['current_attachments'] = array();
211
212
	// Clear out prior attachment activity when starting afresh
213
	if (empty($_REQUEST['message']) && empty($_REQUEST['preview']) && !empty($_SESSION['already_attached']))
214
	{
215
		require_once($sourcedir . '/ManageAttachments.php');
216
		foreach ($_SESSION['already_attached'] as $attachID => $attachment)
217
			removeAttachments(array('id_attach' => $attachID));
218
219
		unset($_SESSION['already_attached']);
220
	}
221
222
	// Don't allow a post if it's locked and you aren't all powerful.
223
	if ($locked && !allowedTo('moderate_board'))
224
		fatal_lang_error('topic_locked', false);
225
	// Check the users permissions - is the user allowed to add or post a poll?
226
	if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1')
227
	{
228
		// New topic, new poll.
229
		if (empty($topic))
230
			isAllowedTo('poll_post');
231
		// This is an old topic - but it is yours!  Can you add to it?
232
		elseif ($user_info['id'] == $id_member_poster && !allowedTo('poll_add_any'))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id_member_poster does not seem to be defined for all execution paths leading up to this point.
Loading history...
233
			isAllowedTo('poll_add_own');
234
		// If you're not the owner, can you add to any poll?
235
		else
236
			isAllowedTo('poll_add_any');
237
238
		if (!empty($board))
239
		{
240
			require_once($sourcedir . '/Subs-Members.php');
241
			$allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
242
			$guest_vote_enabled = in_array(-1, $allowedVoteGroups['allowed']);
243
		}
244
		// No board, so we'll have to check this again in Post2
245
		else
246
			$guest_vote_enabled = true;
247
248
		// Set up the poll options.
249
		$context['poll_options'] = array(
250
			'max_votes' => empty($_POST['poll_max_votes']) ? '1' : max(1, $_POST['poll_max_votes']),
251
			'hide' => empty($_POST['poll_hide']) ? 0 : $_POST['poll_hide'],
252
			'expire' => !isset($_POST['poll_expire']) ? '' : $_POST['poll_expire'],
253
			'change_vote' => isset($_POST['poll_change_vote']),
254
			'guest_vote' => isset($_POST['poll_guest_vote']),
255
			'guest_vote_enabled' => $guest_vote_enabled,
256
		);
257
258
		// Make all five poll choices empty.
259
		$context['choices'] = array(
260
			array('id' => 0, 'number' => 1, 'label' => '', 'is_last' => false),
261
			array('id' => 1, 'number' => 2, 'label' => '', 'is_last' => false),
262
			array('id' => 2, 'number' => 3, 'label' => '', 'is_last' => false),
263
			array('id' => 3, 'number' => 4, 'label' => '', 'is_last' => false),
264
			array('id' => 4, 'number' => 5, 'label' => '', 'is_last' => true)
265
		);
266
		$context['last_choice_id'] = 4;
267
	}
268
269
	if ($context['make_event'])
270
	{
271
		// They might want to pick a board.
272
		if (!isset($context['current_board']))
273
			$context['current_board'] = 0;
274
275
		// Start loading up the event info.
276
		$context['event'] = array();
277
		$context['event']['title'] = isset($_REQUEST['evtitle']) ? $smcFunc['htmlspecialchars'](stripslashes($_REQUEST['evtitle'])) : '';
278
		$context['event']['location'] = isset($_REQUEST['event_location']) ? $smcFunc['htmlspecialchars'](stripslashes($_REQUEST['event_location'])) : '';
279
280
		$context['event']['id'] = isset($_REQUEST['eventid']) ? (int) $_REQUEST['eventid'] : -1;
281
		$context['event']['new'] = $context['event']['id'] == -1;
282
283
		// Permissions check!
284
		isAllowedTo('calendar_post');
285
286
		// We want a fairly compact version of the time, but as close as possible to the user's settings.
287
		if (preg_match('~%[HkIlMpPrRSTX](?:[^%]*%[HkIlMpPrRSTX])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0]))
288
			$time_string = '%k:%M';
289
		else
290
			$time_string = str_replace(array('%I', '%H', '%S', '%r', '%R', '%T'), array('%l', '%k', '', '%l:%M %p', '%k:%M', '%l:%M'), $matches[0]);
291
292
		$js_time_string = str_replace(
293
			array('%H', '%k', '%I', '%l', '%M', '%p', '%P', '%r',      '%R',  '%S', '%T',    '%X'),
294
			array('H',  'G',  'h',  'g',  'i',  'A',  'a',  'h:i:s A', 'H:i', 's',  'H:i:s', 'H:i:s'),
295
			$time_string
296
		);
297
298
		// Editing an event?  (but NOT previewing!?)
299
		if (empty($context['event']['new']) && !isset($_REQUEST['subject']))
300
		{
301
			// If the user doesn't have permission to edit the post in this topic, redirect them.
302
			if ((empty($id_member_poster) || $id_member_poster != $user_info['id'] || !allowedTo('modify_own')) && !allowedTo('modify_any'))
303
			{
304
				require_once($sourcedir . '/Calendar.php');
305
				return CalendarPost();
306
			}
307
308
			// Get the current event information.
309
			require_once($sourcedir . '/Subs-Calendar.php');
310
			$eventProperties = getEventProperties($context['event']['id']);
311
			$context['event'] = array_merge($context['event'], $eventProperties);
312
		}
313
		else
314
		{
315
			// Get the current event information.
316
			require_once($sourcedir . '/Subs-Calendar.php');
317
			$eventProperties = getNewEventDatetimes();
318
			$context['event'] = array_merge($context['event'], $eventProperties);
319
320
			// Make sure the year and month are in the valid range.
321
			if ($context['event']['month'] < 1 || $context['event']['month'] > 12)
322
				fatal_lang_error('invalid_month', false);
323
			if ($context['event']['year'] < $modSettings['cal_minyear'] || $context['event']['year'] > $modSettings['cal_maxyear'])
324
				fatal_lang_error('invalid_year', false);
325
326
			$context['event']['categories'] = $board_list;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $board_list does not seem to be defined for all execution paths leading up to this point.
Loading history...
327
		}
328
329
		// Find the last day of the month.
330
		$context['event']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['event']['month'] == 12 ? 1 : $context['event']['month'] + 1, 0, $context['event']['month'] == 12 ? $context['event']['year'] + 1 : $context['event']['year']));
331
332
		// An all day event? Set up some nice defaults in case the user wants to change that
333
		if ($context['event']['allday'] == true)
334
		{
335
			$context['event']['tz'] = getUserTimezone();
336
			$context['event']['start_time'] = timeformat(time(), $time_string);
0 ignored issues
show
Bug introduced by
It seems like $time_string can also be of type string; however, parameter $show_today of timeformat() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

336
			$context['event']['start_time'] = timeformat(time(), /** @scrutinizer ignore-type */ $time_string);
Loading history...
337
			$context['event']['end_time'] = timeformat(time() + 3600, $time_string);
338
		}
339
		// Otherwise, just adjust these to look nice on the input form
340
		else
341
		{
342
			$context['event']['start_time'] = $context['event']['start_time_orig'];
343
			$context['event']['end_time'] = $context['event']['end_time_orig'];
344
		}
345
346
		// Need this so the user can select a timezone for the event.
347
		$context['all_timezones'] = smf_list_timezones($context['event']['start_date']);
348
		unset($context['all_timezones']['']);
349
350
		// If the event's timezone is not in SMF's standard list of time zones, prepend it to the list
351
		if (!in_array($context['event']['tz'], array_keys($context['all_timezones'])))
352
		{
353
			$d = date_create($context['event']['start_datetime'] . ' ' . $context['event']['tz']);
354
			$context['all_timezones'] = array($context['event']['tz'] => '[UTC' . date_format($d, 'P') . '] - ' . $context['event']['tz']) + $context['all_timezones'];
355
		}
356
357
		loadCSSFile('jquery-ui.datepicker.css', array(), 'smf_datepicker');
358
		loadCSSFile('jquery.timepicker.css', array(), 'smf_timepicker');
359
		loadJavaScriptFile('jquery-ui.datepicker.min.js', array('defer' => true), 'smf_datepicker');
360
		loadJavaScriptFile('jquery.timepicker.min.js', array('defer' => true), 'smf_timepicker');
361
		loadJavaScriptFile('datepair.min.js', array('defer' => true), 'smf_datepair');
362
		addInlineJavaScript('
363
	$("#allday").click(function(){
364
		$("#start_time").attr("disabled", this.checked);
365
		$("#end_time").attr("disabled", this.checked);
366
		$("#tz").attr("disabled", this.checked);
367
	});
368
	$("#event_time_input .date_input").datepicker({
369
		dateFormat: "yy-mm-dd",
370
		autoSize: true,
371
		isRTL: ' . ($context['right_to_left'] ? 'true' : 'false') . ',
372
		constrainInput: true,
373
		showAnim: "",
374
		showButtonPanel: false,
375
		minDate: "' . $modSettings['cal_minyear'] . '-01-01",
376
		maxDate: "' . $modSettings['cal_maxyear'] . '-12-31",
377
		yearRange: "' . $modSettings['cal_minyear'] . ':' . $modSettings['cal_maxyear'] . '",
378
		hideIfNoPrevNext: true,
379
		monthNames: ["' . implode('", "', $txt['months_titles']) . '"],
380
		monthNamesShort: ["' . implode('", "', $txt['months_short']) . '"],
381
		dayNames: ["' . implode('", "', $txt['days']) . '"],
382
		dayNamesShort: ["' . implode('", "', $txt['days_short']) . '"],
383
		dayNamesMin: ["' . implode('", "', $txt['days_short']) . '"],
384
		prevText: "' . $txt['prev_month'] . '",
385
		nextText: "' . $txt['next_month'] . '",
386
	});
387
	$(".time_input").timepicker({
388
		timeFormat: "' . $js_time_string . '",
389
		showDuration: true,
390
		maxTime: "23:59:59",
391
	});
392
	var date_entry = document.getElementById("event_time_input");
393
	var date_entry_pair = new Datepair(date_entry, {
394
		timeClass: "time_input",
395
		dateClass: "date_input",
396
		parseDate: function (el) {
397
		    var utc = new Date($(el).datepicker("getDate"));
398
		    return utc && new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));
399
		},
400
		updateDate: function (el, v) {
401
		    $(el).datepicker("setDate", new Date(v.getTime() - (v.getTimezoneOffset() * 60000)));
402
		}
403
	});
404
	', true);
405
406
		$context['event']['board'] = !empty($board) ? $board : $modSettings['cal_defaultboard'];
407
		$context['event']['topic'] = !empty($topic) ? $topic : 0;
408
	}
409
410
	// See if any new replies have come along.
411
	// Huh, $_REQUEST['msg'] is set upon submit, so this doesn't get executed at submit
412
	// only at preview
413
	if (empty($_REQUEST['msg']) && !empty($topic))
414
	{
415
		if (isset($_REQUEST['last_msg']) && $context['topic_last_message'] > $_REQUEST['last_msg'])
416
		{
417
			$request = $smcFunc['db_query']('', '
418
				SELECT COUNT(*)
419
				FROM {db_prefix}messages
420
				WHERE id_topic = {int:current_topic}
421
					AND id_msg > {int:last_msg}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
422
					AND approved = {int:approved}') . '
423
				LIMIT 1',
424
				array(
425
					'current_topic' => $topic,
426
					'last_msg' => (int) $_REQUEST['last_msg'],
427
					'approved' => 1,
428
				)
429
			);
430
			list ($context['new_replies']) = $smcFunc['db_fetch_row']($request);
431
			$smcFunc['db_free_result']($request);
432
433
			if (!empty($context['new_replies']))
434
			{
435
				if ($context['new_replies'] == 1)
436
					$txt['error_new_replies'] = isset($_GET['last_msg']) ? $txt['error_new_reply_reading'] : $txt['error_new_reply'];
437
				else
438
					$txt['error_new_replies'] = sprintf(isset($_GET['last_msg']) ? $txt['error_new_replies_reading'] : $txt['error_new_replies'], $context['new_replies']);
439
440
				$post_errors[] = 'new_replies';
441
442
				$modSettings['topicSummaryPosts'] = $context['new_replies'] > $modSettings['topicSummaryPosts'] ? max($modSettings['topicSummaryPosts'], 5) : $modSettings['topicSummaryPosts'];
443
			}
444
		}
445
	}
446
447
	// Get a response prefix (like 'Re:') in the default forum language.
448
	if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix')))
449
	{
450
		if ($language === $user_info['language'])
451
			$context['response_prefix'] = $txt['response_prefix'];
452
		else
453
		{
454
			loadLanguage('index', $language, false);
455
			$context['response_prefix'] = $txt['response_prefix'];
456
			loadLanguage('index');
457
		}
458
		cache_put_data('response_prefix', $context['response_prefix'], 600);
459
	}
460
461
	// Previewing, modifying, or posting?
462
	// Do we have a body, but an error happened.
463
	if (isset($_REQUEST['message']) || isset($_REQUEST['quickReply']) || !empty($context['post_error']))
464
	{
465
		if (isset($_REQUEST['quickReply']))
466
			$_REQUEST['message'] = $_REQUEST['quickReply'];
467
468
		// Validate inputs.
469
		if (empty($context['post_error']))
470
		{
471
			// This means they didn't click Post and get an error.
472
			$really_previewing = true;
473
		}
474
		else
475
		{
476
			if (!isset($_REQUEST['subject']))
477
				$_REQUEST['subject'] = '';
478
			if (!isset($_REQUEST['message']))
479
				$_REQUEST['message'] = '';
480
			if (!isset($_REQUEST['icon']))
481
				$_REQUEST['icon'] = 'xx';
482
483
			// They are previewing if they asked to preview (i.e. came from quick reply).
484
			$really_previewing = !empty($_POST['preview']);
485
		}
486
487
		// In order to keep the approval status flowing through, we have to pass it through the form...
488
		$context['becomes_approved'] = empty($_REQUEST['not_approved']);
489
		$context['show_approval'] = isset($_REQUEST['approve']) ? ($_REQUEST['approve'] ? 2 : 1) : 0;
490
		$context['can_announce'] &= $context['becomes_approved'];
491
492
		// Set up the inputs for the form.
493
		$form_subject = strtr($smcFunc['htmlspecialchars']($_REQUEST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
494
		$form_message = $smcFunc['htmlspecialchars']($_REQUEST['message'], ENT_QUOTES);
495
496
		// Make sure the subject isn't too long - taking into account special characters.
497
		if ($smcFunc['strlen']($form_subject) > 100)
498
			$form_subject = $smcFunc['substr']($form_subject, 0, 100);
499
500
		if (isset($_REQUEST['poll']))
501
		{
502
			$context['question'] = isset($_REQUEST['question']) ? $smcFunc['htmlspecialchars'](trim($_REQUEST['question'])) : '';
503
504
			$context['choices'] = array();
505
			$choice_id = 0;
506
507
			$_POST['options'] = empty($_POST['options']) ? array() : htmlspecialchars__recursive($_POST['options']);
508
			foreach ($_POST['options'] as $option)
509
			{
510
				if (trim($option) == '')
511
					continue;
512
513
				$context['choices'][] = array(
514
					'id' => $choice_id++,
515
					'number' => $choice_id,
516
					'label' => $option,
517
					'is_last' => false
518
				);
519
			}
520
521
			// One empty option for those with js disabled...I know are few... :P
522
			$context['choices'][] = array(
523
				'id' => $choice_id++,
524
				'number' => $choice_id,
525
				'label' => '',
526
				'is_last' => false
527
			);
528
529
			if (count($context['choices']) < 2)
530
			{
531
				$context['choices'][] = array(
532
					'id' => $choice_id++,
533
					'number' => $choice_id,
534
					'label' => '',
535
					'is_last' => false
536
				);
537
			}
538
			$context['last_choice_id'] = $choice_id;
539
			$context['choices'][count($context['choices']) - 1]['is_last'] = true;
540
		}
541
542
		// Are you... a guest?
543
		if ($user_info['is_guest'])
544
		{
545
			$_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']);
546
			$_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']);
547
548
			$_REQUEST['guestname'] = $smcFunc['htmlspecialchars']($_REQUEST['guestname']);
549
			$context['name'] = $_REQUEST['guestname'];
550
			$_REQUEST['email'] = $smcFunc['htmlspecialchars']($_REQUEST['email']);
551
			$context['email'] = $_REQUEST['email'];
552
553
			$user_info['name'] = $_REQUEST['guestname'];
554
		}
555
556
		// Only show the preview stuff if they hit Preview.
557
		if (($really_previewing == true || isset($_REQUEST['xml'])) && !isset($_REQUEST['save_draft']))
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
558
		{
559
			// Set up the preview message and subject and censor them...
560
			$context['preview_message'] = $form_message;
561
			preparsecode($form_message, true);
562
			preparsecode($context['preview_message']);
563
564
			// Do all bulletin board code tags, with or without smileys.
565
			$context['preview_message'] = parse_bbc($context['preview_message'], isset($_REQUEST['ns']) ? 0 : 1);
0 ignored issues
show
Bug introduced by
IssetNode ? 0 : 1 of type integer is incompatible with the type boolean expected by parameter $smileys of parse_bbc(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

565
			$context['preview_message'] = parse_bbc($context['preview_message'], /** @scrutinizer ignore-type */ isset($_REQUEST['ns']) ? 0 : 1);
Loading history...
566
			censorText($context['preview_message']);
567
568
			if ($form_subject != '')
569
			{
570
				$context['preview_subject'] = $form_subject;
571
572
				censorText($context['preview_subject']);
573
			}
574
			else
575
				$context['preview_subject'] = '<em>' . $txt['no_subject'] . '</em>';
576
577
			// Protect any CDATA blocks.
578
			if (isset($_REQUEST['xml']))
579
				$context['preview_message'] = strtr($context['preview_message'], array(']]>' => ']]]]><![CDATA[>'));
580
		}
581
582
		// Set up the checkboxes.
583
		$context['notify'] = !empty($_REQUEST['notify']);
584
		$context['use_smileys'] = !isset($_REQUEST['ns']);
585
586
		$context['icon'] = isset($_REQUEST['icon']) ? preg_replace('~[\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : 'xx';
587
588
		// Set the destination action for submission.
589
		$context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] : '') . (isset($_REQUEST['poll']) ? ';poll' : '');
590
		$context['submit_label'] = isset($_REQUEST['msg']) ? $txt['save'] : $txt['post'];
591
592
		// Previewing an edit?
593
		if (isset($_REQUEST['msg']) && !empty($topic))
594
		{
595
			// Get the existing message. Previewing.
596
			$request = $smcFunc['db_query']('', '
597
				SELECT
598
					m.id_member, m.modified_time, m.smileys_enabled, m.body,
599
					m.poster_name, m.poster_email, m.subject, m.icon, m.approved,
600
					COALESCE(a.size, -1) AS filesize, a.filename, a.id_attach,
601
					a.approved AS attachment_approved, t.id_member_started AS id_member_poster,
602
					m.poster_time, log.id_action
603
				FROM {db_prefix}messages AS m
604
					INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
605
					LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type})
606
					LEFT JOIN {db_prefix}log_actions AS log ON (m.id_topic = log.id_topic AND log.action = {string:announce_action})
607
				WHERE m.id_msg = {int:id_msg}
608
					AND m.id_topic = {int:current_topic}',
609
				array(
610
					'current_topic' => $topic,
611
					'attachment_type' => 0,
612
					'id_msg' => $_REQUEST['msg'],
613
					'announce_action' => 'announce_topic',
614
				)
615
			);
616
			// The message they were trying to edit was most likely deleted.
617
			// @todo Change this error message?
618
			if ($smcFunc['db_num_rows']($request) == 0)
619
				fatal_lang_error('no_board', false);
620
			$row = $smcFunc['db_fetch_assoc']($request);
621
622
			$attachment_stuff = array($row);
623
			while ($row2 = $smcFunc['db_fetch_assoc']($request))
624
				$attachment_stuff[] = $row2;
625
			$smcFunc['db_free_result']($request);
626
627
			if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
628
			{
629
				// Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public.
630
				if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
631
					fatal_lang_error('modify_post_time_passed', false);
632
				elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own'))
633
					isAllowedTo('modify_replies');
634
				else
635
					isAllowedTo('modify_own');
636
			}
637
			elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any'))
638
				isAllowedTo('modify_replies');
639
			else
640
				isAllowedTo('modify_any');
641
642
			if ($context['can_announce'] && !empty($row['id_action']))
643
			{
644
				loadLanguage('Errors');
645
				$context['post_error']['messages'][] = $txt['error_topic_already_announced'];
646
			}
647
648
			if (!empty($modSettings['attachmentEnable']))
649
			{
650
				$request = $smcFunc['db_query']('', '
651
					SELECT COALESCE(size, -1) AS filesize, filename, id_attach, approved, mime_type, id_thumb
652
					FROM {db_prefix}attachments
653
					WHERE id_msg = {int:id_msg}
654
						AND attachment_type = {int:attachment_type}
655
					ORDER BY id_attach',
656
					array(
657
						'id_msg' => (int) $_REQUEST['msg'],
658
						'attachment_type' => 0,
659
					)
660
				);
661
662
				while ($row = $smcFunc['db_fetch_assoc']($request))
663
				{
664
					if ($row['filesize'] <= 0)
665
						continue;
666
					$context['current_attachments'][$row['id_attach']] = array(
667
						'name' => $smcFunc['htmlspecialchars']($row['filename']),
668
						'size' => $row['filesize'],
669
						'attachID' => $row['id_attach'],
670
						'approved' => $row['approved'],
671
						'mime_type' => $row['mime_type'],
672
						'thumb' => $row['id_thumb'],
673
					);
674
				}
675
				$smcFunc['db_free_result']($request);
676
			}
677
678
			// Allow moderators to change names....
679
			if (allowedTo('moderate_forum') && !empty($topic))
680
			{
681
				$request = $smcFunc['db_query']('', '
682
					SELECT id_member, poster_name, poster_email
683
					FROM {db_prefix}messages
684
					WHERE id_msg = {int:id_msg}
685
						AND id_topic = {int:current_topic}
686
					LIMIT 1',
687
					array(
688
						'current_topic' => $topic,
689
						'id_msg' => (int) $_REQUEST['msg'],
690
					)
691
				);
692
				$row = $smcFunc['db_fetch_assoc']($request);
693
				$smcFunc['db_free_result']($request);
694
695
				if (empty($row['id_member']))
696
				{
697
					$context['name'] = $smcFunc['htmlspecialchars']($row['poster_name']);
698
					$context['email'] = $smcFunc['htmlspecialchars']($row['poster_email']);
699
				}
700
			}
701
		}
702
703
		// No check is needed, since nothing is really posted.
704
		checkSubmitOnce('free');
705
	}
706
	// Editing a message...
707
	elseif (isset($_REQUEST['msg']) && !empty($topic))
708
	{
709
		$context['editing'] = true;
710
711
		$_REQUEST['msg'] = (int) $_REQUEST['msg'];
712
713
		// Get the existing message. Editing.
714
		$request = $smcFunc['db_query']('', '
715
			SELECT
716
				m.id_member, m.modified_time, m.modified_name, m.modified_reason, m.smileys_enabled, m.body,
717
				m.poster_name, m.poster_email, m.subject, m.icon, m.approved,
718
				COALESCE(a.size, -1) AS filesize, a.filename, a.id_attach, a.mime_type, a.id_thumb,
719
				a.approved AS attachment_approved, t.id_member_started AS id_member_poster,
720
				m.poster_time, log.id_action
721
			FROM {db_prefix}messages AS m
722
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
723
				LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type})
724
					LEFT JOIN {db_prefix}log_actions AS log ON (m.id_topic = log.id_topic AND log.action = {string:announce_action})
725
			WHERE m.id_msg = {int:id_msg}
726
				AND m.id_topic = {int:current_topic}',
727
			array(
728
				'current_topic' => $topic,
729
				'attachment_type' => 0,
730
				'id_msg' => $_REQUEST['msg'],
731
				'announce_action' => 'announce_topic',
732
			)
733
		);
734
		// The message they were trying to edit was most likely deleted.
735
		if ($smcFunc['db_num_rows']($request) == 0)
736
			fatal_lang_error('no_message', false);
737
		$row = $smcFunc['db_fetch_assoc']($request);
738
739
		$attachment_stuff = array($row);
740
		while ($row2 = $smcFunc['db_fetch_assoc']($request))
741
			$attachment_stuff[] = $row2;
742
		$smcFunc['db_free_result']($request);
743
744
		if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
745
		{
746
			// Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public.
747
			if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
748
				fatal_lang_error('modify_post_time_passed', false);
749
			elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own'))
750
				isAllowedTo('modify_replies');
751
			else
752
				isAllowedTo('modify_own');
753
		}
754
		elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any'))
755
			isAllowedTo('modify_replies');
756
		else
757
			isAllowedTo('modify_any');
758
759
		if ($context['can_announce'] && !empty($row['id_action']))
760
		{
761
			loadLanguage('Errors');
762
			$context['post_error']['messages'][] = $txt['error_topic_already_announced'];
763
		}
764
765
		// When was it last modified?
766
		if (!empty($row['modified_time']))
767
		{
768
			$context['last_modified'] = timeformat($row['modified_time']);
769
			$context['last_modified_reason'] = censorText($row['modified_reason']);
770
			$context['last_modified_text'] = sprintf($txt['last_edit_by'], $context['last_modified'], $row['modified_name']) . empty($row['modified_reason']) ? '' : '&nbsp;' . $txt['last_edit_reason'] . ':&nbsp;' . $row['modified_reason'];
771
		}
772
773
		// Get the stuff ready for the form.
774
		$form_subject = $row['subject'];
775
		$form_message = un_preparsecode($row['body']);
776
		censorText($form_message);
777
		censorText($form_subject);
778
779
		// Check the boxes that should be checked.
780
		$context['use_smileys'] = !empty($row['smileys_enabled']);
781
		$context['icon'] = $row['icon'];
782
783
		// Show an "approve" box if the user can approve it, and the message isn't approved.
784
		if (!$row['approved'] && !$context['show_approval'])
785
			$context['show_approval'] = allowedTo('approve_posts');
786
787
		// Sort the attachments so they are in the order saved
788
		$temp = array();
789
		foreach ($attachment_stuff as $attachment)
790
		{
791
			if ($attachment['filesize'] >= 0 && !empty($modSettings['attachmentEnable']))
792
				$temp[$attachment['id_attach']] = $attachment;
793
		}
794
		ksort($temp);
795
796
		// Load up 'em attachments!
797
		foreach ($temp as $attachment)
798
		{
799
			$context['current_attachments'][$attachment['id_attach']] = array(
800
				'name' => $smcFunc['htmlspecialchars']($attachment['filename']),
801
				'size' => $attachment['filesize'],
802
				'attachID' => $attachment['id_attach'],
803
				'approved' => $attachment['attachment_approved'],
804
				'mime_type' => $attachment['mime_type'],
805
				'thumb' => $attachment['id_thumb'],
806
			);
807
		}
808
809
		// Allow moderators to change names....
810
		if (allowedTo('moderate_forum') && empty($row['id_member']))
811
		{
812
			$context['name'] = $smcFunc['htmlspecialchars']($row['poster_name']);
813
			$context['email'] = $smcFunc['htmlspecialchars']($row['poster_email']);
814
		}
815
816
		// Set the destination.
817
		$context['destination'] = 'post2;start=' . $_REQUEST['start'] . ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] . (isset($_REQUEST['poll']) ? ';poll' : '');
818
		$context['submit_label'] = $txt['save'];
819
	}
820
	// Posting...
821
	else
822
	{
823
		// By default....
824
		$context['use_smileys'] = true;
825
		$context['icon'] = 'xx';
826
827
		if ($user_info['is_guest'])
828
		{
829
			$context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : '';
830
			$context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : '';
831
		}
832
		$context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['poll']) ? ';poll' : '');
833
834
		$context['submit_label'] = $txt['post'];
835
836
		// Posting a quoted reply?
837
		if (!empty($topic) && !empty($_REQUEST['quote']))
838
		{
839
			// Make sure they _can_ quote this post, and if so get it.
840
			$request = $smcFunc['db_query']('', '
841
				SELECT m.subject, COALESCE(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.body
842
				FROM {db_prefix}messages AS m
843
					INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND {query_see_board})
844
					LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
845
				WHERE m.id_msg = {int:id_msg}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
846
					AND m.approved = {int:is_approved}') . '
847
				LIMIT 1',
848
				array(
849
					'id_msg' => (int) $_REQUEST['quote'],
850
					'is_approved' => 1,
851
				)
852
			);
853
			if ($smcFunc['db_num_rows']($request) == 0)
854
				fatal_lang_error('quoted_post_deleted', false);
855
			list ($form_subject, $mname, $mdate, $form_message) = $smcFunc['db_fetch_row']($request);
856
			$smcFunc['db_free_result']($request);
857
858
			// Add 'Re: ' to the front of the quoted subject.
859
			if (trim($context['response_prefix']) != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0)
860
				$form_subject = $context['response_prefix'] . $form_subject;
861
862
			// Censor the message and subject.
863
			censorText($form_message);
864
			censorText($form_subject);
865
866
			// But if it's in HTML world, turn them into htmlspecialchar's so they can be edited!
867
			if (strpos($form_message, '[html]') !== false)
868
			{
869
				$parts = preg_split('~(\[/code\]|\[code(?:=[^\]]+)?\])~i', $form_message, -1, PREG_SPLIT_DELIM_CAPTURE);
870
				for ($i = 0, $n = count($parts); $i < $n; $i++)
0 ignored issues
show
Bug introduced by
It seems like $parts can also be of type false; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

870
				for ($i = 0, $n = count(/** @scrutinizer ignore-type */ $parts); $i < $n; $i++)
Loading history...
871
				{
872
					// It goes 0 = outside, 1 = begin tag, 2 = inside, 3 = close tag, repeat.
873
					if ($i % 4 == 0)
874
						$parts[$i] = preg_replace_callback('~\[html\](.+?)\[/html\]~is', function($m)
875
						{
876
							return '[html]' . preg_replace('~<br\s?/?' . '>~i', '&lt;br /&gt;<br>', "$m[1]") . '[/html]';
877
						}, $parts[$i]);
878
				}
879
				$form_message = implode('', $parts);
0 ignored issues
show
Bug introduced by
It seems like $parts can also be of type false; however, parameter $pieces of implode() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

879
				$form_message = implode('', /** @scrutinizer ignore-type */ $parts);
Loading history...
880
			}
881
882
			$form_message = preg_replace('~<br ?/?' . '>~i', "\n", $form_message);
883
884
			// Remove any nested quotes, if necessary.
885
			if (!empty($modSettings['removeNestedQuotes']))
886
				$form_message = preg_replace(array('~\n?\[quote.*?\].+?\[/quote\]\n?~is', '~^\n~', '~\[/quote\]~'), '', $form_message);
887
888
			// Add a quote string on the front and end.
889
			$form_message = '[quote author=' . $mname . ' link=msg=' . (int) $_REQUEST['quote'] . ' date=' . $mdate . ']' . "\n" . rtrim($form_message) . "\n" . '[/quote]';
890
		}
891
		// Posting a reply without a quote?
892
		elseif (!empty($topic) && empty($_REQUEST['quote']))
893
		{
894
			// Get the first message's subject.
895
			$form_subject = $first_subject;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $first_subject does not seem to be defined for all execution paths leading up to this point.
Loading history...
896
897
			// Add 'Re: ' to the front of the subject.
898
			if (trim($context['response_prefix']) != '' && $form_subject != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0)
899
				$form_subject = $context['response_prefix'] . $form_subject;
900
901
			// Censor the subject.
902
			censorText($form_subject);
903
904
			$form_message = '';
905
		}
906
		else
907
		{
908
			$form_subject = isset($_GET['subject']) ? $_GET['subject'] : '';
909
			$form_message = '';
910
		}
911
	}
912
913
	$context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment', $boards, true) || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments', $boards, true)));
914
915
	if ($context['can_post_attachment'])
916
	{
917
		// If there are attachments, calculate the total size and how many.
918
		$context['attachments']['total_size'] = 0;
919
		$context['attachments']['quantity'] = 0;
920
921
		// If this isn't a new post, check the current attachments.
922
		if (isset($_REQUEST['msg']))
923
		{
924
			$context['attachments']['quantity'] = count($context['current_attachments']);
925
			foreach ($context['current_attachments'] as $attachment)
926
				$context['attachments']['total_size'] += $attachment['size'];
927
		}
928
929
		// A bit of house keeping first.
930
		if (!empty($_SESSION['temp_attachments']) && count($_SESSION['temp_attachments']) == 1)
931
			unset($_SESSION['temp_attachments']);
932
933
		if (!empty($_SESSION['temp_attachments']))
934
		{
935
			// Is this a request to delete them?
936
			if (isset($_GET['delete_temp']))
937
			{
938
				foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
939
				{
940
					if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false)
941
						if (file_exists($attachment['tmp_name']))
942
							unlink($attachment['tmp_name']);
943
				}
944
				$post_errors[] = 'temp_attachments_gone';
945
				$_SESSION['temp_attachments'] = array();
946
			}
947
			// Hmm, coming in fresh and there are files in session.
948
			elseif ($context['current_action'] != 'post2' || !empty($_POST['from_qr']))
949
			{
950
				// Let's be nice and see if they belong here first.
951
				if ((empty($_REQUEST['msg']) && empty($_SESSION['temp_attachments']['post']['msg']) && $_SESSION['temp_attachments']['post']['board'] == (!empty($board) ? $board : 0)) || (!empty($_REQUEST['msg']) && $_SESSION['temp_attachments']['post']['msg'] == $_REQUEST['msg']))
952
				{
953
					// See if any files still exist before showing the warning message and the files attached.
954
					foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
955
					{
956
						if (strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
957
							continue;
958
959
						if (file_exists($attachment['tmp_name']))
960
						{
961
							$post_errors[] = 'temp_attachments_new';
962
							$context['files_in_session_warning'] = $txt['attached_files_in_session'];
963
							unset($_SESSION['temp_attachments']['post']['files']);
964
							break;
965
						}
966
					}
967
				}
968
				else
969
				{
970
					// Since, they don't belong here. Let's inform the user that they exist..
971
					if (!empty($topic))
972
						$delete_url = $scripturl . '?action=post' . (!empty($_REQUEST['msg']) ? (';msg=' . $_REQUEST['msg']) : '') . (!empty($_REQUEST['last_msg']) ? (';last_msg=' . $_REQUEST['last_msg']) : '') . ';topic=' . $topic . ';delete_temp';
973
					else
974
						$delete_url = $scripturl . '?action=post' . (!empty($board) ? ';board=' . $board : '') . ';delete_temp';
975
976
					// Compile a list of the files to show the user.
977
					$file_list = array();
978
					foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
979
						if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false)
980
							$file_list[] = $attachment['name'];
981
982
					$_SESSION['temp_attachments']['post']['files'] = $file_list;
983
					$file_list = '<div class="attachments">' . implode('<br>', $file_list) . '</div>';
984
985
					if (!empty($_SESSION['temp_attachments']['post']['msg']))
986
					{
987
						// We have a message id, so we can link back to the old topic they were trying to edit..
988
						$goback_url = $scripturl . '?action=post' . (!empty($_SESSION['temp_attachments']['post']['msg']) ? (';msg=' . $_SESSION['temp_attachments']['post']['msg']) : '') . (!empty($_SESSION['temp_attachments']['post']['last_msg']) ? (';last_msg=' . $_SESSION['temp_attachments']['post']['last_msg']) : '') . ';topic=' . $_SESSION['temp_attachments']['post']['topic'] . ';additionalOptions';
989
990
						$post_errors[] = array('temp_attachments_found', array($delete_url, $goback_url, $file_list));
991
						$context['ignore_temp_attachments'] = true;
992
					}
993
					else
994
					{
995
						$post_errors[] = array('temp_attachments_lost', array($delete_url, $file_list));
996
						$context['ignore_temp_attachments'] = true;
997
					}
998
				}
999
			}
1000
1001
			if (!empty($context['we_are_history']))
1002
				$post_errors[] = $context['we_are_history'];
1003
1004
			foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
1005
			{
1006
				if (isset($context['ignore_temp_attachments']) || isset($_SESSION['temp_attachments']['post']['files']))
1007
					break;
1008
1009
				if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
1010
					continue;
1011
1012
				if ($attachID == 'initial_error')
1013
				{
1014
					$txt['error_attach_initial_error'] = $txt['attach_no_upload'] . '<div style="padding: 0 1em;">' . (is_array($attachment) ? vsprintf($txt[$attachment[0]], $attachment[1]) : $txt[$attachment]) . '</div>';
1015
					$post_errors[] = 'attach_initial_error';
1016
					unset($_SESSION['temp_attachments']);
1017
					break;
1018
				}
1019
1020
				// Show any errors which might have occurred.
1021
				if (!empty($attachment['errors']))
1022
				{
1023
					$txt['error_attach_errors'] = empty($txt['error_attach_errors']) ? '<br>' : '';
1024
					$txt['error_attach_errors'] .= vsprintf($txt['attach_warning'], $attachment['name']) . '<div style="padding: 0 1em;">';
1025
					foreach ($attachment['errors'] as $error)
1026
						$txt['error_attach_errors'] .= (is_array($error) ? vsprintf($txt[$error[0]], $error[1]) : $txt[$error]) . '<br >';
1027
					$txt['error_attach_errors'] .= '</div>';
1028
					$post_errors[] = 'attach_errors';
1029
1030
					// Take out the trash.
1031
					unset($_SESSION['temp_attachments'][$attachID]);
1032
					if (file_exists($attachment['tmp_name']))
1033
						unlink($attachment['tmp_name']);
1034
					continue;
1035
				}
1036
1037
				// More house keeping.
1038
				if (!file_exists($attachment['tmp_name']))
1039
				{
1040
					unset($_SESSION['temp_attachments'][$attachID]);
1041
					continue;
1042
				}
1043
1044
				$context['attachments']['quantity']++;
1045
				$context['attachments']['total_size'] += $attachment['size'];
1046
				if (!isset($context['files_in_session_warning']))
1047
					$context['files_in_session_warning'] = $txt['attached_files_in_session'];
1048
1049
				$context['current_attachments'][$attachID] = array(
1050
					'name' => '<u>' . $smcFunc['htmlspecialchars']($attachment['name']) . '</u>',
1051
					'size' => $attachment['size'],
1052
					'attachID' => $attachID,
1053
					'unchecked' => false,
1054
					'approved' => 1,
1055
					'mime_type' => '',
1056
					'thumb' => 0,
1057
				);
1058
			}
1059
		}
1060
	}
1061
1062
	// Do we need to show the visual verification image?
1063
	$context['require_verification'] = !$user_info['is_mod'] && !$user_info['is_admin'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || ($user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1));
1064
	if ($context['require_verification'])
1065
	{
1066
		require_once($sourcedir . '/Subs-Editor.php');
1067
		$verificationOptions = array(
1068
			'id' => 'post',
1069
		);
1070
		$context['require_verification'] = create_control_verification($verificationOptions);
1071
		$context['visual_verification_id'] = $verificationOptions['id'];
1072
	}
1073
1074
	// If they came from quick reply, and have to enter verification details, give them some notice.
1075
	if (!empty($_REQUEST['from_qr']) && !empty($context['require_verification']))
1076
		$post_errors[] = 'need_qr_verification';
1077
1078
	/*
1079
	 * There are two error types: serious and minor. Serious errors
1080
	 * actually tell the user that a real error has occurred, while minor
1081
	 * errors are like warnings that let them know that something with
1082
	 * their post isn't right.
1083
	 */
1084
	$minor_errors = array('not_approved', 'new_replies', 'old_topic', 'need_qr_verification', 'no_subject', 'topic_locked', 'topic_unlocked', 'topic_stickied', 'topic_unstickied', 'cannot_post_attachment');
1085
1086
	call_integration_hook('integrate_post_errors', array(&$post_errors, &$minor_errors));
1087
1088
	// Any errors occurred?
1089
	if (!empty($post_errors))
1090
	{
1091
		loadLanguage('Errors');
1092
		$context['error_type'] = 'minor';
1093
		foreach ($post_errors as $post_error)
1094
			if (is_array($post_error))
1095
			{
1096
				$post_error_id = $post_error[0];
1097
				$context['post_error'][$post_error_id] = vsprintf($txt['error_' . $post_error_id], $post_error[1]);
1098
1099
				// If it's not a minor error flag it as such.
1100
				if (!in_array($post_error_id, $minor_errors))
1101
					$context['error_type'] = 'serious';
1102
			}
1103
			else
1104
			{
1105
				$context['post_error'][$post_error] = $txt['error_' . $post_error];
1106
1107
				// If it's not a minor error flag it as such.
1108
				if (!in_array($post_error, $minor_errors))
1109
					$context['error_type'] = 'serious';
1110
			}
1111
	}
1112
1113
	// What are you doing? Posting a poll, modifying, previewing, new post, or reply...
1114
	if (isset($_REQUEST['poll']))
1115
		$context['page_title'] = $txt['new_poll'];
1116
	elseif ($context['make_event'])
1117
		$context['page_title'] = $context['event']['id'] == -1 ? $txt['calendar_post_event'] : $txt['calendar_edit'];
1118
	elseif (isset($_REQUEST['msg']))
1119
		$context['page_title'] = $txt['modify_msg'];
1120
	elseif (isset($_REQUEST['subject'], $context['preview_subject']))
1121
		$context['page_title'] = $txt['preview'] . ' - ' . strip_tags($context['preview_subject']);
1122
	elseif (empty($topic))
1123
		$context['page_title'] = $txt['start_new_topic'];
1124
	else
1125
		$context['page_title'] = $txt['post_reply'];
1126
1127
	// Build the link tree.
1128
	if (empty($topic))
1129
		$context['linktree'][] = array(
1130
			'name' => '<em>' . $txt['start_new_topic'] . '</em>'
1131
		);
1132
	else
1133
		$context['linktree'][] = array(
1134
			'url' => $scripturl . '?topic=' . $topic . '.' . $_REQUEST['start'],
1135
			'name' => $form_subject,
1136
			'extra_before' => '<span><strong class="nav">' . $context['page_title'] . ' (</strong></span>',
1137
			'extra_after' => '<span><strong class="nav">)</strong></span>'
1138
		);
1139
1140
	$context['subject'] = addcslashes($form_subject, '"');
1141
	$context['message'] = str_replace(array('"', '<', '>', '&nbsp;'), array('&quot;', '&lt;', '&gt;', ' '), $form_message);
1142
1143
	// Are post drafts enabled?
1144
	$context['drafts_save'] = !empty($modSettings['drafts_post_enabled']) && allowedTo('post_draft');
1145
	$context['drafts_autosave'] = !empty($context['drafts_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('post_autosave_draft');
1146
1147
	// Build a list of drafts that they can load in to the editor
1148
	if (!empty($context['drafts_save']))
1149
	{
1150
		require_once($sourcedir . '/Drafts.php');
1151
		ShowDrafts($user_info['id'], $topic);
1152
	}
1153
1154
	// Needed for the editor and message icons.
1155
	require_once($sourcedir . '/Subs-Editor.php');
1156
1157
	// Now create the editor.
1158
	$editorOptions = array(
1159
		'id' => 'message',
1160
		'value' => $context['message'],
1161
		'labels' => array(
1162
			'post_button' => $context['submit_label'],
1163
		),
1164
		// add height and width for the editor
1165
		'height' => '275px',
1166
		'width' => '100%',
1167
		// We do XML preview here.
1168
		'preview_type' => 2,
1169
		'required' => true,
1170
	);
1171
	create_control_richedit($editorOptions);
1172
1173
	// Store the ID.
1174
	$context['post_box_name'] = $editorOptions['id'];
1175
1176
	$context['attached'] = '';
1177
	$context['make_poll'] = isset($_REQUEST['poll']);
1178
1179
	// Message icons - customized icons are off?
1180
	$context['icons'] = getMessageIcons(!empty($board) ? $board : 0);
1181
1182
	if (!empty($context['icons']))
1183
		$context['icons'][count($context['icons']) - 1]['is_last'] = true;
1184
1185
	// Are we starting a poll? if set the poll icon as selected if its available
1186
	if (isset($_REQUEST['poll']))
1187
	{
1188
		foreach ($context['icons'] as $icons)
1189
		{
1190
			if (isset($icons['value']) && $icons['value'] == 'poll')
1191
			{
1192
				// if found we are done
1193
				$context['icon'] = 'poll';
1194
				break;
1195
			}
1196
		}
1197
	}
1198
1199
	$context['icon_url'] = '';
1200
	for ($i = 0, $n = count($context['icons']); $i < $n; $i++)
1201
	{
1202
		$context['icons'][$i]['selected'] = $context['icon'] == $context['icons'][$i]['value'];
1203
		if ($context['icons'][$i]['selected'])
1204
			$context['icon_url'] = $context['icons'][$i]['url'];
1205
	}
1206
	if (empty($context['icon_url']))
1207
	{
1208
		$context['icon_url'] = $settings[file_exists($settings['theme_dir'] . '/images/post/' . $context['icon'] . '.png') ? 'images_url' : 'default_images_url'] . '/post/' . $context['icon'] . '.png';
1209
		array_unshift($context['icons'], array(
1210
			'value' => $context['icon'],
1211
			'name' => $txt['current_icon'],
1212
			'url' => $context['icon_url'],
1213
			'is_last' => empty($context['icons']),
1214
			'selected' => true,
1215
		));
1216
	}
1217
1218
	if (!empty($topic) && !empty($modSettings['topicSummaryPosts']))
1219
		getTopic();
1220
1221
	// If the user can post attachments prepare the warning labels.
1222
	if ($context['can_post_attachment'])
1223
	{
1224
		// If they've unchecked an attachment, they may still want to attach that many more files, but don't allow more than num_allowed_attachments.
1225
		$context['num_allowed_attachments'] = empty($modSettings['attachmentNumPerPostLimit']) ? 50 : min($modSettings['attachmentNumPerPostLimit'] - count($context['current_attachments']), $modSettings['attachmentNumPerPostLimit']);
1226
		$context['can_post_attachment_unapproved'] = allowedTo('post_attachment');
1227
		$context['attachment_restrictions'] = array();
1228
		$context['allowed_extensions'] = strtr(strtolower($modSettings['attachmentExtensions']), array(',' => ', '));
1229
		$attachmentRestrictionTypes = array('attachmentNumPerPostLimit', 'attachmentPostLimit', 'attachmentSizeLimit');
1230
		foreach ($attachmentRestrictionTypes as $type)
1231
			if (!empty($modSettings[$type]))
1232
			{
1233
				// Show the max number of attachments if not 0.
1234
				if ($type == 'attachmentNumPerPostLimit')
1235
					$context['attachment_restrictions'][] = sprintf($txt['attach_remaining'], $modSettings['attachmentNumPerPostLimit'] - $context['attachments']['quantity']);
1236
			}
1237
	}
1238
1239
	$context['back_to_topic'] = isset($_REQUEST['goback']) || (isset($_REQUEST['msg']) && !isset($_REQUEST['subject']));
1240
	$context['show_additional_options'] = !empty($_POST['additional_options']) || isset($_SESSION['temp_attachments']['post']) || isset($_GET['additionalOptions']);
1241
1242
	$context['is_new_topic'] = empty($topic);
1243
	$context['is_new_post'] = !isset($_REQUEST['msg']);
1244
	$context['is_first_post'] = $context['is_new_topic'] || (isset($_REQUEST['msg']) && $_REQUEST['msg'] == $id_first_msg);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id_first_msg does not seem to be defined for all execution paths leading up to this point.
Loading history...
1245
1246
	// WYSIWYG only works if BBC is enabled
1247
	$modSettings['disable_wysiwyg'] = !empty($modSettings['disable_wysiwyg']) || empty($modSettings['enableBBC']);
1248
1249
	// Register this form in the session variables.
1250
	checkSubmitOnce('register');
1251
1252
	// Mentions
1253
	if (!empty($modSettings['enable_mentions']) && allowedTo('mention'))
1254
	{
1255
		loadJavaScriptFile('jquery.caret.min.js', array('defer' => true), 'smf_caret');
1256
		loadJavaScriptFile('jquery.atwho.min.js', array('defer' => true), 'smf_atwho');
1257
		loadJavaScriptFile('mentions.js', array('defer' => true, 'minimize' => true), 'smf_mentions');
1258
	}
1259
1260
	// quotedText.js
1261
	loadJavaScriptFile('quotedText.js', array('defer' => true, 'minimize' => true), 'smf_quotedText');
1262
1263
	// Mock files to show already attached files.
1264
	addInlineJavaScript('
1265
	var current_attachments = [];');
1266
1267
	if (!empty($context['current_attachments']))
1268
	{
1269
		foreach ($context['current_attachments'] as $key => $mock)
1270
			addInlineJavaScript('
1271
	current_attachments.push({
1272
		name: '. JavaScriptEscape($mock['name']) . ',
1273
		size: '. $mock['size'] . ',
1274
		attachID: '. $mock['attachID'] . ',
1275
		approved: '. $mock['approved'] . ',
1276
		type: '. JavaScriptEscape(!empty($mock['mime_type']) ? $mock['mime_type'] : '') . ',
1277
		thumbID: '. (!empty($mock['thumb']) ? $mock['thumb'] : 0) . '
1278
	});');
1279
	}
1280
1281
	// File Upload.
1282
	if ($context['can_post_attachment'])
1283
	{
1284
		$acceptedFiles = implode(',', array_map(function($val) use($smcFunc) { return '.' . $smcFunc['htmltrim']($val); } , explode(',', $context['allowed_extensions'])));
1285
1286
		loadJavaScriptFile('dropzone.min.js', array('defer' => true), 'smf_dropzone');
1287
		loadJavaScriptFile('smf_fileUpload.js', array('defer' => true, 'minimize' => true), 'smf_fileUpload');
1288
		addInlineJavaScript('
1289
	$(function() {
1290
		smf_fileUpload({
1291
			dictDefaultMessage : '. JavaScriptEscape($txt['attach_drop_zone']) . ',
1292
			dictFallbackMessage : '. JavaScriptEscape($txt['attach_drop_zone_no']) . ',
1293
			dictCancelUpload : '. JavaScriptEscape($txt['modify_cancel']) . ',
1294
			genericError: '. JavaScriptEscape($txt['attach_php_error']) . ',
1295
			text_attachLeft: '. JavaScriptEscape($txt['attached_attachedLeft']) . ',
1296
			text_deleteAttach: '. JavaScriptEscape($txt['attached_file_delete']) . ',
1297
			text_attachDeleted: '. JavaScriptEscape($txt['attached_file_deleted']) . ',
1298
			text_insertBBC: '. JavaScriptEscape($txt['attached_insertBBC']) . ',
1299
			text_attachUploaded: '. JavaScriptEscape($txt['attached_file_uploaded']) . ',
1300
			text_attach_unlimited: '. JavaScriptEscape($txt['attach_drop_unlimited']) . ',
1301
			text_totalMaxSize: '. JavaScriptEscape($txt['attach_max_total_file_size_current']) . ',
1302
			text_max_size_progress: '. JavaScriptEscape($txt['attach_max_size_progress']) . ',
1303
			dictMaxFilesExceeded: '. JavaScriptEscape($txt['more_attachments_error']) . ',
1304
			dictInvalidFileType: '. JavaScriptEscape(sprintf($txt['cant_upload_type'], $context['allowed_extensions'])) . ',
1305
			dictFileTooBig: '. JavaScriptEscape(sprintf($txt['file_too_big'], comma_format($modSettings['attachmentSizeLimit'], 0))) . ',
1306
			acceptedFiles: '. JavaScriptEscape($acceptedFiles) . ',
1307
			thumbnailWidth: '.(!empty($modSettings['attachmentThumbWidth']) ? $modSettings['attachmentThumbWidth'] : 'null') . ',
1308
			thumbnailHeight: '.(!empty($modSettings['attachmentThumbHeight']) ? $modSettings['attachmentThumbHeight'] : 'null') . ',
1309
			limitMultiFileUploadSize:'. round(max($modSettings['attachmentPostLimit'] - ($context['attachments']['total_size'] / 1024), 0)) * 1024 . ',
1310
			maxFileAmount: '. (!empty($context['num_allowed_attachments']) ? $context['num_allowed_attachments'] : 'null') . ',
1311
			maxTotalSize: ' . (!empty($modSettings['attachmentPostLimit']) ? $modSettings['attachmentPostLimit'] : '0') . ',
1312
			maxFileSize: '. (!empty($modSettings['attachmentSizeLimit']) ? $modSettings['attachmentSizeLimit'] : '0') . ',
1313
		});
1314
	});', true);
1315
	}
1316
1317
	// Knowing the current board ID might be handy.
1318
	addInlineJavaScript('
1319
	var current_board = '. (empty($context['current_board']) ? 'null' : $context['current_board']) . ';', false);
1320
1321
	// Now let's set up the fields for the posting form header...
1322
	$context['posting_fields'] = array();
1323
1324
	// Guests must supply their name and email.
1325
	if (isset($context['name']) && isset($context['email']))
1326
	{
1327
		$context['posting_fields']['guestname'] = array(
1328
			'label' => array(
1329
				'text' => $txt['name'],
1330
				'class' => isset($context['post_error']['long_name']) || isset($context['post_error']['no_name']) || isset($context['post_error']['bad_name']) ? 'error' : '',
1331
			),
1332
			'input' => array(
1333
				'type' => 'text',
1334
				'attributes' => array(
1335
					'size' => 25,
1336
					'value' => $context['name'],
1337
					'required' => true,
1338
				),
1339
			),
1340
		);
1341
1342
		if (empty($modSettings['guest_post_no_email']))
1343
		{
1344
			$context['posting_fields']['email'] = array(
1345
				'label' => array(
1346
					'text' => $txt['email'],
1347
					'class' => isset($context['post_error']['no_email']) || isset($context['post_error']['bad_email']) ? 'error' : '',
1348
				),
1349
				'input' => array(
1350
					'type' => 'email',
1351
					'attributes' => array(
1352
						'size' => 25,
1353
						'value' => $context['email'],
1354
						'required' => true,
1355
					),
1356
				),
1357
			);
1358
		}
1359
	}
1360
1361
	// Gotta post it somewhere.
1362
	if (empty($board) && !$context['make_event'])
1363
	{
1364
		$context['posting_fields']['board'] = array(
1365
			'label' => array(
1366
				'text' => $txt['calendar_post_in'],
1367
			),
1368
			'input' => array(
1369
				'type' => 'select',
1370
				'options' => array(),
1371
			),
1372
		);
1373
		foreach ($board_list as $category)
1374
		{
1375
			$context['posting_fields']['board']['input']['options'][$category['name']] = array('options' => array());
1376
1377
			foreach ($category['boards'] as $brd)
1378
				$context['posting_fields']['board']['input']['options'][$category['name']]['options'][$brd['name']]['attributes'] = array(
1379
					'value' => $brd['id'],
1380
					'selected' => (bool) $brd['selected'],
1381
					'label' => ($brd['child_level'] > 0 ? str_repeat('==', $brd['child_level'] - 1) . '=&gt;' : '') . ' ' . $brd['name'],
1382
				);
1383
		}
1384
	}
1385
1386
	// Gotta have a subject.
1387
	$context['posting_fields']['subject'] = array(
1388
		'label' => array(
1389
			'text' => $txt['subject'],
1390
			'class' => isset($context['post_error']['no_subject']) ? 'error' : '',
1391
		),
1392
		'input' => array(
1393
			'type' => 'text',
1394
			'attributes' => array(
1395
				'size' => 80,
1396
				'maxlength' => !empty($topic) ? 84 : 80,
1397
				'value' => $context['subject'],
1398
				'required' => true,
1399
			),
1400
		),
1401
	);
1402
1403
	// Icons are fun.
1404
	$context['posting_fields']['icon'] = array(
1405
		'label' => array(
1406
			'text' => $txt['message_icon'],
1407
		),
1408
		'input' => array(
1409
			'type' => 'select',
1410
			'attributes' => array(
1411
				'id' => 'icon',
1412
				'onchange' => 'showimage();',
1413
			),
1414
			'options' => array(),
1415
			'after' => ' <img id="icons" src="' . $context['icon_url'] . '">',
1416
		),
1417
	);
1418
	foreach ($context['icons'] as $icon)
1419
	{
1420
		$context['posting_fields']['icon']['input']['options'][$icon['name']]['attributes'] = array(
1421
			'value' => $icon['value'],
1422
			'selected' => $icon['value'] == $context['icon'],
1423
		);
1424
	}
1425
1426
1427
	// Finally, load the template.
1428
	if (!isset($_REQUEST['xml']))
1429
		loadTemplate('Post');
1430
1431
	call_integration_hook('integrate_post_end');
1432
}
1433
1434
/**
1435
 * Posts or saves the message composed with Post().
1436
 *
1437
 * requires various permissions depending on the action.
1438
 * handles attachment, post, and calendar saving.
1439
 * sends off notifications, and allows for announcements and moderation.
1440
 * accessed from ?action=post2.
1441
 */
1442
function Post2()
1443
{
1444
	global $board, $topic, $txt, $modSettings, $sourcedir, $context;
1445
	global $user_info, $board_info, $smcFunc, $settings;
1446
1447
	// Sneaking off, are we?
1448
	if (empty($_POST) && empty($topic))
1449
	{
1450
		if (empty($_SERVER['CONTENT_LENGTH']))
1451
			redirectexit('action=post;board=' . $board . '.0');
1452
		else
1453
			fatal_lang_error('post_upload_error', false);
1454
	}
1455
	elseif (empty($_POST) && !empty($topic))
1456
		redirectexit('action=post;topic=' . $topic . '.0');
1457
1458
	// No need!
1459
	$context['robot_no_index'] = true;
1460
1461
	// Prevent double submission of this form.
1462
	checkSubmitOnce('check');
1463
1464
	// No errors as yet.
1465
	$post_errors = array();
1466
1467
	// If the session has timed out, let the user re-submit their form.
1468
	if (checkSession('post', '', false) != '')
1469
		$post_errors[] = 'session_timeout';
1470
1471
	// Wrong verification code?
1472
	if (!$user_info['is_admin'] && !$user_info['is_mod'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || ($user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1)))
1473
	{
1474
		require_once($sourcedir . '/Subs-Editor.php');
1475
		$verificationOptions = array(
1476
			'id' => 'post',
1477
		);
1478
		$context['require_verification'] = create_control_verification($verificationOptions, true);
1479
		if (is_array($context['require_verification']))
1480
			$post_errors = array_merge($post_errors, $context['require_verification']);
1481
	}
1482
1483
	require_once($sourcedir . '/Subs-Post.php');
1484
	loadLanguage('Post');
1485
1486
	call_integration_hook('integrate_post2_start');
1487
1488
	// Drafts enabled and needed?
1489
	if (!empty($modSettings['drafts_post_enabled']) && (isset($_POST['save_draft']) || isset($_POST['id_draft'])))
1490
		require_once($sourcedir . '/Drafts.php');
1491
1492
	// First check to see if they are trying to delete any current attachments.
1493
	if (isset($_POST['attach_del']))
1494
	{
1495
		$keep_temp = array();
1496
		$keep_ids = array();
1497
		foreach ($_POST['attach_del'] as $dummy)
1498
			if (strpos($dummy, 'post_tmp_' . $user_info['id']) !== false)
1499
				$keep_temp[] = $dummy;
1500
			else
1501
				$keep_ids[] = (int) $dummy;
1502
1503
		if (isset($_SESSION['temp_attachments']))
1504
			foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
1505
			{
1506
				if ((isset($_SESSION['temp_attachments']['post']['files'], $attachment['name']) && in_array($attachment['name'], $_SESSION['temp_attachments']['post']['files'])) || in_array($attachID, $keep_temp) || strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
1507
					continue;
1508
1509
				unset($_SESSION['temp_attachments'][$attachID]);
1510
				unlink($attachment['tmp_name']);
1511
			}
1512
1513
		if (!empty($_REQUEST['msg']))
1514
		{
1515
			require_once($sourcedir . '/ManageAttachments.php');
1516
			$attachmentQuery = array(
1517
				'attachment_type' => 0,
1518
				'id_msg' => (int) $_REQUEST['msg'],
1519
				'not_id_attach' => $keep_ids,
1520
			);
1521
			removeAttachments($attachmentQuery);
1522
		}
1523
	}
1524
1525
	// Then try to upload any attachments.
1526
	$context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments')));
1527
	if ($context['can_post_attachment'] && empty($_POST['from_qr']))
1528
	{
1529
		require_once($sourcedir . '/Subs-Attachments.php');
1530
		processAttachments();
1531
	}
1532
1533
	// They've already uploaded some attachments, but they don't have permission to post them
1534
	// This can sometimes happen when they came from ?action=calendar;sa=post
1535
	if (!$context['can_post_attachment'] && !empty($_SESSION['already_attached']))
1536
	{
1537
		require_once($sourcedir . '/ManageAttachments.php');
1538
1539
		foreach ($_SESSION['already_attached'] as $attachID => $attachment)
1540
			removeAttachments(array('id_attach' => $attachID));
1541
1542
		unset($_SESSION['already_attached']);
1543
1544
		$post_errors[] = array('cannot_post_attachment', array($board_info['name']));
1545
	}
1546
1547
	// If this isn't a new topic load the topic info that we need.
1548
	if (!empty($topic))
1549
	{
1550
		$request = $smcFunc['db_query']('', '
1551
			SELECT locked, is_sticky, id_poll, approved, id_first_msg, id_last_msg, id_member_started, id_board
1552
			FROM {db_prefix}topics
1553
			WHERE id_topic = {int:current_topic}
1554
			LIMIT 1',
1555
			array(
1556
				'current_topic' => $topic,
1557
			)
1558
		);
1559
		$topic_info = $smcFunc['db_fetch_assoc']($request);
1560
		$smcFunc['db_free_result']($request);
1561
1562
		// Though the topic should be there, it might have vanished.
1563
		if (!is_array($topic_info))
1564
			fatal_lang_error('topic_doesnt_exist', 404);
1565
1566
		// Did this topic suddenly move? Just checking...
1567
		if ($topic_info['id_board'] != $board)
1568
			fatal_lang_error('not_a_topic');
1569
1570
		// Do the permissions and approval stuff...
1571
		$becomesApproved = true;
1572
		$topicAndMessageBothUnapproved = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $topicAndMessageBothUnapproved is dead and can be removed.
Loading history...
1573
1574
		// If the topic is unapproved the message automatically becomes unapproved too.
1575
		if (empty($topic_info['approved']))
1576
		{
1577
			$becomesApproved = false;
1578
1579
			// camelCase fan much? :P
1580
			$topicAndMessageBothUnapproved = true;
1581
1582
			// Set a nice session var...
1583
			$_SESSION['becomesUnapproved'] = true;
1584
		}
1585
	}
1586
1587
	// Replying to a topic?
1588
	if (!empty($topic) && !isset($_REQUEST['msg']))
1589
	{
1590
		// Don't allow a post if it's locked.
1591
		if ($topic_info['locked'] != 0 && !allowedTo('moderate_board'))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $topic_info does not seem to be defined for all execution paths leading up to this point.
Loading history...
1592
			fatal_lang_error('topic_locked', false);
1593
1594
		// Sorry, multiple polls aren't allowed... yet.  You should stop giving me ideas :P.
1595
		if (isset($_REQUEST['poll']) && $topic_info['id_poll'] > 0)
1596
			unset($_REQUEST['poll']);
1597
1598
		elseif ($topic_info['id_member_started'] != $user_info['id'])
1599
		{
1600
			if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any'))
1601
				$becomesApproved = false;
1602
1603
			else
1604
				isAllowedTo('post_reply_any');
1605
		}
1606
		elseif (!allowedTo('post_reply_any'))
1607
		{
1608
			if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own'))
1609
				$becomesApproved = false;
1610
1611
			else
1612
				isAllowedTo('post_reply_own');
1613
		}
1614
1615
		if (isset($_POST['lock']))
1616
		{
1617
			// Nothing is changed to the lock.
1618
			if (empty($topic_info['locked']) == empty($_POST['lock']))
1619
				unset($_POST['lock']);
1620
1621
			// You're have no permission to lock this topic.
1622
			elseif (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']))
1623
				unset($_POST['lock']);
1624
1625
			// You are allowed to (un)lock your own topic only.
1626
			elseif (!allowedTo('lock_any'))
1627
			{
1628
				// You cannot override a moderator lock.
1629
				if ($topic_info['locked'] == 1)
1630
					unset($_POST['lock']);
1631
1632
				else
1633
					$_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
1634
			}
1635
			// Hail mighty moderator, (un)lock this topic immediately.
1636
			else
1637
			{
1638
				$_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
1639
1640
				// Did someone (un)lock this while you were posting?
1641
				if (isset($_POST['already_locked']) && $_POST['already_locked'] != $topic_info['locked'])
1642
					$post_errors[] = 'topic_' . (empty($topic_info['locked']) ? 'un' : '') . 'locked';
1643
			}
1644
		}
1645
1646
		// So you wanna (un)sticky this...let's see.
1647
		if (isset($_POST['sticky']) && ($_POST['sticky'] == $topic_info['is_sticky'] || !allowedTo('make_sticky')))
1648
			unset($_POST['sticky']);
1649
		elseif (isset($_POST['sticky']))
1650
		{
1651
			// Did someone (un)sticky this while you were posting?
1652
			if (isset($_POST['already_sticky']) && $_POST['already_sticky'] != $topic_info['is_sticky'])
1653
				$post_errors[] = 'topic_' . (empty($topic_info['is_sticky']) ? 'un' : '') . 'sticky';
1654
		}
1655
1656
		// If drafts are enabled, then pass this off
1657
		if (!empty($modSettings['drafts_post_enabled']) && isset($_POST['save_draft']))
1658
		{
1659
			SaveDraft($post_errors);
1660
			return Post();
1661
		}
1662
1663
		// If the number of replies has changed, if the setting is enabled, go back to Post() - which handles the error.
1664
		if (isset($_POST['last_msg']) && $topic_info['id_last_msg'] > $_POST['last_msg'])
1665
		{
1666
			$_REQUEST['preview'] = true;
1667
			return Post();
1668
		}
1669
1670
		$posterIsGuest = $user_info['is_guest'];
1671
	}
1672
	// Posting a new topic.
1673
	elseif (empty($topic))
1674
	{
1675
		// Now don't be silly, new topics will get their own id_msg soon enough.
1676
		unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
1677
1678
		// Do like, the permissions, for safety and stuff...
1679
		$becomesApproved = true;
1680
		if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics'))
1681
			$becomesApproved = false;
1682
		else
1683
			isAllowedTo('post_new');
1684
1685
		if (isset($_POST['lock']))
1686
		{
1687
			// New topics are by default not locked.
1688
			if (empty($_POST['lock']))
1689
				unset($_POST['lock']);
1690
			// Besides, you need permission.
1691
			elseif (!allowedTo(array('lock_any', 'lock_own')))
1692
				unset($_POST['lock']);
1693
			// A moderator-lock (1) can override a user-lock (2).
1694
			else
1695
				$_POST['lock'] = allowedTo('lock_any') ? 1 : 2;
1696
		}
1697
1698
		if (isset($_POST['sticky']) && (empty($_POST['sticky']) || !allowedTo('make_sticky')))
1699
			unset($_POST['sticky']);
1700
1701
		// Saving your new topic as a draft first?
1702
		if (!empty($modSettings['drafts_post_enabled']) && isset($_POST['save_draft']))
1703
		{
1704
			SaveDraft($post_errors);
1705
			return Post();
1706
		}
1707
1708
		$posterIsGuest = $user_info['is_guest'];
1709
	}
1710
	// Modifying an existing message?
1711
	elseif (isset($_REQUEST['msg']) && !empty($topic))
1712
	{
1713
		$_REQUEST['msg'] = (int) $_REQUEST['msg'];
1714
1715
		$request = $smcFunc['db_query']('', '
1716
			SELECT id_member, poster_name, poster_email, poster_time, approved
1717
			FROM {db_prefix}messages
1718
			WHERE id_msg = {int:id_msg}
1719
			LIMIT 1',
1720
			array(
1721
				'id_msg' => $_REQUEST['msg'],
1722
			)
1723
		);
1724
		if ($smcFunc['db_num_rows']($request) == 0)
1725
			fatal_lang_error('cant_find_messages', false);
1726
		$row = $smcFunc['db_fetch_assoc']($request);
1727
		$smcFunc['db_free_result']($request);
1728
1729
		if (!empty($topic_info['locked']) && !allowedTo('moderate_board'))
1730
			fatal_lang_error('topic_locked', false);
1731
1732
		if (isset($_POST['lock']))
1733
		{
1734
			// Nothing changes to the lock status.
1735
			if ((empty($_POST['lock']) && empty($topic_info['locked'])) || (!empty($_POST['lock']) && !empty($topic_info['locked'])))
1736
				unset($_POST['lock']);
1737
			// You're simply not allowed to (un)lock this.
1738
			elseif (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']))
1739
				unset($_POST['lock']);
1740
			// You're only allowed to lock your own topics.
1741
			elseif (!allowedTo('lock_any'))
1742
			{
1743
				// You're not allowed to break a moderator's lock.
1744
				if ($topic_info['locked'] == 1)
1745
					unset($_POST['lock']);
1746
				// Lock it with a soft lock or unlock it.
1747
				else
1748
					$_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
1749
			}
1750
			// You must be the moderator.
1751
			else
1752
			{
1753
				$_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
1754
1755
				// Did someone (un)lock this while you were posting?
1756
				if (isset($_POST['already_locked']) && $_POST['already_locked'] != $topic_info['locked'])
1757
					$post_errors[] = 'topic_' . (empty($topic_info['locked']) ? 'un' : '') . 'locked';
1758
			}
1759
		}
1760
1761
		// Change the sticky status of this topic?
1762
		if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $topic_info['is_sticky']))
1763
			unset($_POST['sticky']);
1764
		elseif (isset($_POST['sticky']))
1765
		{
1766
			// Did someone (un)sticky this while you were posting?
1767
			if (isset($_POST['already_sticky']) && $_POST['already_sticky'] != $topic_info['is_sticky'])
1768
				$post_errors[] = 'topic_' . (empty($topic_info['locked']) ? 'un' : '') . 'stickied';
1769
		}
1770
1771
		if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
1772
		{
1773
			if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
1774
				fatal_lang_error('modify_post_time_passed', false);
1775
			elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_own'))
1776
				isAllowedTo('modify_replies');
1777
			else
1778
				isAllowedTo('modify_own');
1779
		}
1780
		elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_any'))
1781
		{
1782
			isAllowedTo('modify_replies');
1783
1784
			// If you're modifying a reply, I say it better be logged...
1785
			$moderationAction = true;
1786
		}
1787
		else
1788
		{
1789
			isAllowedTo('modify_any');
1790
1791
			// Log it, assuming you're not modifying your own post.
1792
			if ($row['id_member'] != $user_info['id'])
1793
				$moderationAction = true;
1794
		}
1795
1796
		// If drafts are enabled, then lets send this off to save
1797
		if (!empty($modSettings['drafts_post_enabled']) && isset($_POST['save_draft']))
1798
		{
1799
			SaveDraft($post_errors);
1800
			return Post();
1801
		}
1802
1803
		$posterIsGuest = empty($row['id_member']);
1804
1805
		// Can they approve it?
1806
		$can_approve = allowedTo('approve_posts');
1807
		$approve_checked = (!empty($REQUEST['approve']) ? 1 : 0);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $REQUEST does not exist. Did you maybe mean $_REQUEST?
Loading history...
1808
		$becomesApproved = $modSettings['postmod_active'] ? ($can_approve && !$row['approved'] ? $approve_checked : $row['approved']) : 1;
1809
		$approve_has_changed = $row['approved'] != $becomesApproved;
1810
1811
		if (!allowedTo('moderate_forum') || !$posterIsGuest)
1812
		{
1813
			$_POST['guestname'] = $row['poster_name'];
1814
			$_POST['email'] = $row['poster_email'];
1815
		}
1816
1817
		// Update search api
1818
		require_once($sourcedir . '/Search.php');
1819
		$searchAPI = findSearchAPI();
1820
		if ($searchAPI->supportsMethod('postRemoved'))
1821
			$searchAPI->postRemoved($_REQUEST['msg']);
1822
1823
	}
1824
1825
	// In case we have approval permissions and want to override.
1826
	if (allowedTo('approve_posts') && $modSettings['postmod_active'])
1827
	{
1828
		// If 'approve' wasn't specified, assume true for these users
1829
		$becomesApproved = !isset($_REQUEST['approve']) || !empty($_REQUEST['approve']) ? 1 : 0;
1830
		$approve_has_changed = isset($row['approved']) ? $row['approved'] != $becomesApproved : false;
1831
	}
1832
1833
	// If the poster is a guest evaluate the legality of name and email.
1834
	if ($posterIsGuest)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $posterIsGuest does not seem to be defined for all execution paths leading up to this point.
Loading history...
1835
	{
1836
		$_POST['guestname'] = !isset($_POST['guestname']) ? '' : trim($_POST['guestname']);
1837
		$_POST['email'] = !isset($_POST['email']) ? '' : trim($_POST['email']);
1838
1839
		if ($_POST['guestname'] == '' || $_POST['guestname'] == '_')
1840
			$post_errors[] = 'no_name';
1841
		if ($smcFunc['strlen']($_POST['guestname']) > 25)
1842
			$post_errors[] = 'long_name';
1843
1844
		if (empty($modSettings['guest_post_no_email']))
1845
		{
1846
			// Only check if they changed it!
1847
			if (!isset($row) || $row['poster_email'] != $_POST['email'])
1848
			{
1849
				if (!allowedTo('moderate_forum') && (!isset($_POST['email']) || $_POST['email'] == ''))
1850
					$post_errors[] = 'no_email';
1851
				if (!allowedTo('moderate_forum') && !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL))
1852
					$post_errors[] = 'bad_email';
1853
			}
1854
1855
			// Now make sure this email address is not banned from posting.
1856
			isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
1857
		}
1858
1859
		// In case they are making multiple posts this visit, help them along by storing their name.
1860
		if (empty($post_errors))
1861
		{
1862
			$_SESSION['guest_name'] = $_POST['guestname'];
1863
			$_SESSION['guest_email'] = $_POST['email'];
1864
		}
1865
	}
1866
1867
	// Coming from the quickReply?
1868
	if (isset($_POST['quickReply']))
1869
		$_POST['message'] = $_POST['quickReply'];
1870
1871
	// Check the subject and message.
1872
	if (!isset($_POST['subject']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['subject'])) === '')
1873
		$post_errors[] = 'no_subject';
1874
	if (!isset($_POST['message']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['message']), ENT_QUOTES) === '')
1875
		$post_errors[] = 'no_message';
1876
	elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_POST['message']) > $modSettings['max_messageLength'])
1877
		$post_errors[] = array('long_message', array($modSettings['max_messageLength']));
1878
	else
1879
	{
1880
		// Prepare the message a bit for some additional testing.
1881
		$_POST['message'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
1882
1883
		// Preparse code. (Zef)
1884
		if ($user_info['is_guest'])
1885
			$user_info['name'] = $_POST['guestname'];
1886
		preparsecode($_POST['message']);
1887
1888
		// Let's see if there's still some content left without the tags.
1889
		if ($smcFunc['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), implode('', $context['allowed_html_tags']))) === '' && (!allowedTo('admin_forum') || strpos($_POST['message'], '[html]') === false))
1890
			$post_errors[] = 'no_message';
1891
1892
	}
1893
	if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && $smcFunc['htmltrim']($_POST['evtitle']) === '')
1894
		$post_errors[] = 'no_event';
1895
	// You are not!
1896
	if (isset($_POST['message']) && strtolower($_POST['message']) == 'i am the administrator.' && !$user_info['is_admin'])
1897
		fatal_error('Knave! Masquerader! Charlatan!', false);
1898
1899
	// Validate the poll...
1900
	if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1')
1901
	{
1902
		if (!empty($topic) && !isset($_REQUEST['msg']))
1903
			fatal_lang_error('no_access', false);
1904
1905
		// This is a new topic... so it's a new poll.
1906
		if (empty($topic))
1907
			isAllowedTo('poll_post');
1908
		// Can you add to your own topics?
1909
		elseif ($user_info['id'] == $topic_info['id_member_started'] && !allowedTo('poll_add_any'))
1910
			isAllowedTo('poll_add_own');
1911
		// Can you add polls to any topic, then?
1912
		else
1913
			isAllowedTo('poll_add_any');
1914
1915
		if (!isset($_POST['question']) || trim($_POST['question']) == '')
1916
			$post_errors[] = 'no_question';
1917
1918
		$_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']);
1919
1920
		// Get rid of empty ones.
1921
		foreach ($_POST['options'] as $k => $option)
1922
			if ($option == '')
1923
				unset($_POST['options'][$k], $_POST['options'][$k]);
1924
1925
		// What are you going to vote between with one choice?!?
1926
		if (count($_POST['options']) < 2)
1927
			$post_errors[] = 'poll_few';
1928
		elseif (count($_POST['options']) > 256)
1929
			$post_errors[] = 'poll_many';
1930
	}
1931
1932
	if ($posterIsGuest)
1933
	{
1934
		// If user is a guest, make sure the chosen name isn't taken.
1935
		require_once($sourcedir . '/Subs-Members.php');
1936
		if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($row['poster_name']) || $_POST['guestname'] != $row['poster_name']))
1937
			$post_errors[] = 'bad_name';
1938
	}
1939
	// If the user isn't a guest, get his or her name and email.
1940
	elseif (!isset($_REQUEST['msg']))
1941
	{
1942
		$_POST['guestname'] = $user_info['username'];
1943
		$_POST['email'] = $user_info['email'];
1944
	}
1945
1946
	// Any mistakes?
1947
	if (!empty($post_errors))
1948
	{
1949
		// Previewing.
1950
		$_REQUEST['preview'] = true;
1951
1952
		return Post($post_errors);
1953
	}
1954
1955
	// Previewing? Go back to start.
1956
	if (isset($_REQUEST['preview']))
1957
	{
1958
		if (checkSession('post', '', false) != '')
1959
		{
1960
			loadLanguage('Errors');
1961
			$post_errors[] = 'session_timeout';
1962
			unset ($_POST['preview'], $_REQUEST['xml']); // just in case
1963
		}
1964
		return Post($post_errors);
1965
	}
1966
1967
	// Make sure the user isn't spamming the board.
1968
	if (!isset($_REQUEST['msg']))
1969
		spamProtection('post');
1970
1971
	// At about this point, we're posting and that's that.
1972
	ignore_user_abort(true);
1973
	@set_time_limit(300);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for set_time_limit(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

1973
	/** @scrutinizer ignore-unhandled */ @set_time_limit(300);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1974
1975
	// Add special html entities to the subject, name, and email.
1976
	$_POST['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
1977
	$_POST['guestname'] = $smcFunc['htmlspecialchars']($_POST['guestname']);
1978
	$_POST['email'] = $smcFunc['htmlspecialchars']($_POST['email']);
1979
	$_POST['modify_reason'] = empty($_POST['modify_reason']) ? '' : strtr($smcFunc['htmlspecialchars']($_POST['modify_reason']), array("\r" => '', "\n" => '', "\t" => ''));
1980
1981
	// At this point, we want to make sure the subject isn't too long.
1982
	if ($smcFunc['strlen']($_POST['subject']) > 100)
1983
		$_POST['subject'] = $smcFunc['substr']($_POST['subject'], 0, 100);
1984
1985
	// Same with the "why did you edit this" text.
1986
	if ($smcFunc['strlen']($_POST['modify_reason']) > 100)
1987
		$_POST['modify_reason'] = $smcFunc['substr']($_POST['modify_reason'], 0, 100);
1988
1989
	// Make the poll...
1990
	if (isset($_REQUEST['poll']))
1991
	{
1992
		// Make sure that the user has not entered a ridiculous number of options..
1993
		if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0)
1994
			$_POST['poll_max_votes'] = 1;
1995
		elseif ($_POST['poll_max_votes'] > count($_POST['options']))
1996
			$_POST['poll_max_votes'] = count($_POST['options']);
1997
		else
1998
			$_POST['poll_max_votes'] = (int) $_POST['poll_max_votes'];
1999
2000
		$_POST['poll_expire'] = (int) $_POST['poll_expire'];
2001
		$_POST['poll_expire'] = $_POST['poll_expire'] > 9999 ? 9999 : ($_POST['poll_expire'] < 0 ? 0 : $_POST['poll_expire']);
2002
2003
		// Just set it to zero if it's not there..
2004
		if (!isset($_POST['poll_hide']))
2005
			$_POST['poll_hide'] = 0;
2006
		else
2007
			$_POST['poll_hide'] = (int) $_POST['poll_hide'];
2008
		$_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0;
2009
2010
		$_POST['poll_guest_vote'] = isset($_POST['poll_guest_vote']) ? 1 : 0;
2011
		// Make sure guests are actually allowed to vote generally.
2012
		if ($_POST['poll_guest_vote'])
2013
		{
2014
			require_once($sourcedir . '/Subs-Members.php');
2015
			$allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
2016
			if (!in_array(-1, $allowedVoteGroups['allowed']))
2017
				$_POST['poll_guest_vote'] = 0;
2018
		}
2019
2020
		// If the user tries to set the poll too far in advance, don't let them.
2021
		if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1)
2022
			fatal_lang_error('poll_range_error', false);
2023
		// Don't allow them to select option 2 for hidden results if it's not time limited.
2024
		elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2)
2025
			$_POST['poll_hide'] = 1;
2026
2027
		// Clean up the question and answers.
2028
		$_POST['question'] = $smcFunc['htmlspecialchars']($_POST['question']);
2029
		$_POST['question'] = $smcFunc['truncate']($_POST['question'], 255);
2030
		$_POST['question'] = preg_replace('~&amp;#(\d{4,5}|[2-9]\d{2,4}|1[2-9]\d);~', '&#$1;', $_POST['question']);
2031
		$_POST['options'] = htmlspecialchars__recursive($_POST['options']);
2032
	}
2033
2034
	// ...or attach a new file...
2035
	if ($context['can_post_attachment'] && !empty($_SESSION['temp_attachments']) && empty($_POST['from_qr']))
2036
	{
2037
		$attachIDs = array();
2038
		$attach_errors = array();
2039
		if (!empty($context['we_are_history']))
2040
			$attach_errors[] = '<dd>' . $txt['error_temp_attachments_flushed'] . '<br><br></dd>';
2041
2042
		foreach ($_SESSION['temp_attachments'] as  $attachID => $attachment)
2043
		{
2044
			if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
2045
				continue;
2046
2047
			// If there was an initial error just show that message.
2048
			if ($attachID == 'initial_error')
2049
			{
2050
				$attach_errors[] = '<dt>' . $txt['attach_no_upload'] . '</dt>';
2051
				$attach_errors[] = '<dd>' . (is_array($attachment) ? vsprintf($txt[$attachment[0]], $attachment[1]) : $txt[$attachment]) . '</dd>';
2052
2053
				unset($_SESSION['temp_attachments']);
2054
				break;
2055
			}
2056
2057
			$attachmentOptions = array(
2058
				'post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0,
2059
				'poster' => $user_info['id'],
2060
				'name' => $attachment['name'],
2061
				'tmp_name' => $attachment['tmp_name'],
2062
				'size' => isset($attachment['size']) ? $attachment['size'] : 0,
2063
				'mime_type' => isset($attachment['type']) ? $attachment['type'] : '',
2064
				'id_folder' => isset($attachment['id_folder']) ? $attachment['id_folder'] : $modSettings['currentAttachmentUploadDir'],
2065
				'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment'),
2066
				'errors' => $attachment['errors'],
2067
			);
2068
2069
			if (empty($attachment['errors']))
2070
			{
2071
				if (createAttachment($attachmentOptions))
2072
				{
2073
					$attachIDs[] = $attachmentOptions['id'];
2074
					if (!empty($attachmentOptions['thumb']))
2075
						$attachIDs[] = $attachmentOptions['thumb'];
2076
				}
2077
			}
2078
			else
2079
				$attach_errors[] = '<dt>&nbsp;</dt>';
2080
2081
			if (!empty($attachmentOptions['errors']))
2082
			{
2083
				// Sort out the errors for display and delete any associated files.
2084
				$attach_errors[] = '<dt>' . vsprintf($txt['attach_warning'], $attachment['name']) . '</dt>';
2085
				$log_these = array('attachments_no_create', 'attachments_no_write', 'attach_timeout', 'ran_out_of_space', 'cant_access_upload_path', 'attach_0_byte_file');
2086
				foreach ($attachmentOptions['errors'] as $error)
2087
				{
2088
					if (!is_array($error))
2089
					{
2090
						$attach_errors[] = '<dd>' . $txt[$error] . '</dd>';
2091
						if (in_array($error, $log_these))
2092
							log_error($attachment['name'] . ': ' . $txt[$error], 'critical');
2093
					}
2094
					else
2095
						$attach_errors[] = '<dd>' . vsprintf($txt[$error[0]], $error[1]) . '</dd>';
2096
				}
2097
				if (file_exists($attachment['tmp_name']))
2098
					unlink($attachment['tmp_name']);
2099
			}
2100
		}
2101
		unset($_SESSION['temp_attachments']);
2102
	}
2103
2104
	// Make the poll...
2105
	if (isset($_REQUEST['poll']))
2106
	{
2107
		// Create the poll.
2108
		$id_poll = $smcFunc['db_insert']('',
2109
			'{db_prefix}polls',
2110
			array(
2111
				'question' => 'string-255', 'hide_results' => 'int', 'max_votes' => 'int', 'expire_time' => 'int', 'id_member' => 'int',
2112
				'poster_name' => 'string-255', 'change_vote' => 'int', 'guest_vote' => 'int'
2113
			),
2114
			array(
2115
				$_POST['question'], $_POST['poll_hide'], $_POST['poll_max_votes'], (empty($_POST['poll_expire']) ? 0 : time() + $_POST['poll_expire'] * 3600 * 24), $user_info['id'],
2116
				$_POST['guestname'], $_POST['poll_change_vote'], $_POST['poll_guest_vote'],
2117
			),
2118
			array('id_poll'),
2119
			1
2120
		);
2121
2122
		// Create each answer choice.
2123
		$i = 0;
2124
		$pollOptions = array();
2125
		foreach ($_POST['options'] as $option)
2126
		{
2127
			$pollOptions[] = array($id_poll, $i, $option);
2128
			$i++;
2129
		}
2130
2131
		$smcFunc['db_insert']('insert',
2132
			'{db_prefix}poll_choices',
2133
			array('id_poll' => 'int', 'id_choice' => 'int', 'label' => 'string-255'),
2134
			$pollOptions,
2135
			array('id_poll', 'id_choice')
2136
		);
2137
2138
		call_integration_hook('integrate_poll_add_edit', array($id_poll, false));
2139
	}
2140
	else
2141
		$id_poll = 0;
2142
2143
	// Creating a new topic?
2144
	$newTopic = empty($_REQUEST['msg']) && empty($topic);
2145
2146
	// Check the icon.
2147
	if (!isset($_POST['icon']))
2148
		$_POST['icon'] = 'xx';
2149
2150
	else
2151
	{
2152
		$_POST['icon'] = $smcFunc['htmlspecialchars']($_POST['icon']);
2153
2154
		// Need to figure it out if this is a valid icon name.
2155
		if ((!file_exists($settings['theme_dir'] . '/images/post/' . $_POST['icon'] . '.png')) && (!file_exists($settings['default_theme_dir'] . '/images/post/' . $_POST['icon'] . '.png')))
2156
			$_POST['icon'] = 'xx';
2157
	}
2158
2159
	// Collect all parameters for the creation or modification of a post.
2160
	$msgOptions = array(
2161
		'id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'],
2162
		'subject' => $_POST['subject'],
2163
		'body' => $_POST['message'],
2164
		'icon' => preg_replace('~[\./\\\\*:"\'<>]~', '', $_POST['icon']),
2165
		'smileys_enabled' => !isset($_POST['ns']),
2166
		'attachments' => empty($attachIDs) ? array() : $attachIDs,
2167
		'approved' => $becomesApproved,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $becomesApproved does not seem to be defined for all execution paths leading up to this point.
Loading history...
2168
	);
2169
	$topicOptions = array(
2170
		'id' => empty($topic) ? 0 : $topic,
2171
		'board' => $board,
2172
		'poll' => isset($_REQUEST['poll']) ? $id_poll : null,
2173
		'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null,
2174
		'sticky_mode' => isset($_POST['sticky']) ? (int) $_POST['sticky'] : null,
2175
		'mark_as_read' => true,
2176
		'is_approved' => !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']),
2177
	);
2178
	$posterOptions = array(
2179
		'id' => $user_info['id'],
2180
		'name' => $_POST['guestname'],
2181
		'email' => $_POST['email'],
2182
		'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count'],
2183
	);
2184
2185
	// This is an already existing message. Edit it.
2186
	if (!empty($_REQUEST['msg']))
2187
	{
2188
		// Have admins allowed people to hide their screwups?
2189
		if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $row does not seem to be defined for all execution paths leading up to this point.
Loading history...
2190
		{
2191
			$msgOptions['modify_time'] = time();
2192
			$msgOptions['modify_name'] = $user_info['name'];
2193
			$msgOptions['modify_reason'] = $_POST['modify_reason'];
2194
		}
2195
2196
		// This will save some time...
2197
		if (empty($approve_has_changed))
2198
			unset($msgOptions['approved']);
2199
2200
		modifyPost($msgOptions, $topicOptions, $posterOptions);
2201
	}
2202
	// This is a new topic or an already existing one. Save it.
2203
	else
2204
	{
2205
		createPost($msgOptions, $topicOptions, $posterOptions);
2206
2207
		if (isset($topicOptions['id']))
2208
			$topic = $topicOptions['id'];
2209
	}
2210
2211
	// Are there attachments already uploaded and waiting to be assigned?
2212
	if (!empty($msgOptions['id']) && !empty($_SESSION['already_attached']))
2213
	{
2214
		require_once($sourcedir . '/Subs-Attachments.php');
2215
		assignAttachments($_SESSION['already_attached'], $msgOptions['id']);
2216
		unset($_SESSION['already_attached']);
2217
	}
2218
2219
	// If we had a draft for this, its time to remove it since it was just posted
2220
	if (!empty($modSettings['drafts_post_enabled']) && !empty($_POST['id_draft']))
2221
		DeleteDraft($_POST['id_draft']);
2222
2223
	// Editing or posting an event?
2224
	if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1))
2225
	{
2226
		require_once($sourcedir . '/Subs-Calendar.php');
2227
2228
		// Make sure they can link an event to this post.
2229
		canLinkEvent();
2230
2231
		// Insert the event.
2232
		$eventOptions = array(
2233
			'board' => $board,
2234
			'topic' => $topic,
2235
			'title' => $_POST['evtitle'],
2236
			'location' => $_POST['event_location'],
2237
			'member' => $user_info['id'],
2238
		);
2239
		insertEvent($eventOptions);
2240
	}
2241
	elseif (isset($_POST['calendar']))
2242
	{
2243
		$_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
2244
2245
		// Validate the post...
2246
		require_once($sourcedir . '/Subs-Calendar.php');
2247
		validateEventPost();
2248
2249
		// If you're not allowed to edit any events, you have to be the poster.
2250
		if (!allowedTo('calendar_edit_any'))
2251
		{
2252
			// Get the event's poster.
2253
			$request = $smcFunc['db_query']('', '
2254
				SELECT id_member
2255
				FROM {db_prefix}calendar
2256
				WHERE id_event = {int:id_event}',
2257
				array(
2258
					'id_event' => $_REQUEST['eventid'],
2259
				)
2260
			);
2261
			$row2 = $smcFunc['db_fetch_assoc']($request);
2262
			$smcFunc['db_free_result']($request);
2263
2264
			// Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...)
2265
			isAllowedTo('calendar_edit_' . ($row2['id_member'] == $user_info['id'] ? 'own' : 'any'));
2266
		}
2267
2268
		// Delete it?
2269
		if (isset($_REQUEST['deleteevent']))
2270
			$smcFunc['db_query']('', '
2271
				DELETE FROM {db_prefix}calendar
2272
				WHERE id_event = {int:id_event}',
2273
				array(
2274
					'id_event' => $_REQUEST['eventid'],
2275
				)
2276
			);
2277
		// ... or just update it?
2278
		else
2279
		{
2280
			// Set up our options
2281
			$eventOptions = array(
2282
				'board' => $board,
2283
				'topic' => $topic,
2284
				'title' => $_POST['evtitle'],
2285
				'location' => $_POST['event_location'],
2286
				'member' => $user_info['id'],
2287
			);
2288
			modifyEvent($_REQUEST['eventid'], $eventOptions);
2289
		}
2290
	}
2291
2292
	// Marking read should be done even for editing messages....
2293
	// Mark all the parents read.  (since you just posted and they will be unread.)
2294
	if (!$user_info['is_guest'] && !empty($board_info['parent_boards']))
2295
	{
2296
		$smcFunc['db_query']('', '
2297
			UPDATE {db_prefix}log_boards
2298
			SET id_msg = {int:id_msg}
2299
			WHERE id_member = {int:current_member}
2300
				AND id_board IN ({array_int:board_list})',
2301
			array(
2302
				'current_member' => $user_info['id'],
2303
				'board_list' => array_keys($board_info['parent_boards']),
2304
				'id_msg' => $modSettings['maxMsgID'],
2305
			)
2306
		);
2307
	}
2308
2309
	// Turn notification on or off.  (note this just blows smoke if it's already on or off.)
2310
	if (!empty($_POST['notify']) && !$context['user']['is_guest'])
2311
	{
2312
		$smcFunc['db_insert']('ignore',
2313
			'{db_prefix}log_notify',
2314
			array('id_member' => 'int', 'id_topic' => 'int', 'id_board' => 'int'),
2315
			array($user_info['id'], $topic, 0),
2316
			array('id_member', 'id_topic', 'id_board')
2317
		);
2318
	}
2319
	elseif (!$newTopic)
2320
		$smcFunc['db_query']('', '
2321
			DELETE FROM {db_prefix}log_notify
2322
			WHERE id_member = {int:current_member}
2323
				AND id_topic = {int:current_topic}',
2324
			array(
2325
				'current_member' => $user_info['id'],
2326
				'current_topic' => $topic,
2327
			)
2328
		);
2329
2330
	// Log an act of moderation - modifying.
2331
	if (!empty($moderationAction))
2332
		logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $row['id_member'], 'board' => $board));
2333
2334
	if (isset($_POST['lock']) && $_POST['lock'] != 2)
2335
		logAction(empty($_POST['lock']) ? 'unlock' : 'lock', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
2336
2337
	if (isset($_POST['sticky']))
2338
		logAction(empty($_POST['sticky']) ? 'unsticky' : 'sticky', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
2339
2340
	// Returning to the topic?
2341
	if (!empty($_REQUEST['goback']))
2342
	{
2343
		// Mark the board as read.... because it might get confusing otherwise.
2344
		$smcFunc['db_query']('', '
2345
			UPDATE {db_prefix}log_boards
2346
			SET id_msg = {int:maxMsgID}
2347
			WHERE id_member = {int:current_member}
2348
				AND id_board = {int:current_board}',
2349
			array(
2350
				'current_board' => $board,
2351
				'current_member' => $user_info['id'],
2352
				'maxMsgID' => $modSettings['maxMsgID'],
2353
			)
2354
		);
2355
	}
2356
2357
	if ($board_info['num_topics'] == 0)
2358
		cache_put_data('board-' . $board, null, 120);
2359
2360
	call_integration_hook('integrate_post2_end');
2361
2362
	if (!empty($_POST['announce_topic']) && allowedTo('announce_topic'))
2363
		redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback'));
2364
2365
	if (!empty($_POST['move']) && allowedTo('move_any'))
2366
		redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
2367
2368
	// Return to post if the mod is on.
2369
	if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback']))
2370
		redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], isBrowser('ie'));
2371
	elseif (!empty($_REQUEST['goback']))
2372
		redirectexit('topic=' . $topic . '.new#new', isBrowser('ie'));
2373
	// Dut-dut-duh-duh-DUH-duh-dut-duh-duh!  *dances to the Final Fantasy Fanfare...*
2374
	else
2375
		redirectexit('board=' . $board . '.0');
2376
}
2377
2378
/**
2379
 * Handle the announce topic function (action=announce).
2380
 *
2381
 * checks the topic announcement permissions and loads the announcement template.
2382
 * requires the announce_topic permission.
2383
 * uses the ManageMembers template and Post language file.
2384
 * call the right function based on the sub-action.
2385
 */
2386
function AnnounceTopic()
2387
{
2388
	global $context, $txt, $topic;
2389
2390
	isAllowedTo('announce_topic');
2391
2392
	validateSession();
2393
2394
	if (empty($topic))
2395
		fatal_lang_error('topic_gone', false);
2396
2397
	loadLanguage('Post');
2398
	loadTemplate('Post');
2399
2400
	$subActions = array(
2401
		'selectgroup' => 'AnnouncementSelectMembergroup',
2402
		'send' => 'AnnouncementSend',
2403
	);
2404
2405
	$context['page_title'] = $txt['announce_topic'];
2406
2407
	// Call the function based on the sub-action.
2408
	$call = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'selectgroup';
2409
	call_helper($subActions[$call]);
2410
}
2411
2412
/**
2413
 * Allow a user to chose the membergroups to send the announcement to.
2414
 *
2415
 * lets the user select the membergroups that will receive the topic announcement.
2416
 */
2417
function AnnouncementSelectMembergroup()
2418
{
2419
	global $txt, $context, $topic, $board_info, $smcFunc;
2420
2421
	$groups = array_merge($board_info['groups'], array(1));
2422
	foreach ($groups as $id => $group)
2423
		$groups[$id] = (int) $group;
2424
2425
	$context['groups'] = array();
2426
	if (in_array(0, $groups))
2427
	{
2428
		$context['groups'][0] = array(
2429
			'id' => 0,
2430
			'name' => $txt['announce_regular_members'],
2431
			'member_count' => 'n/a',
2432
		);
2433
	}
2434
2435
	// Get all membergroups that have access to the board the announcement was made on.
2436
	$request = $smcFunc['db_query']('', '
2437
		SELECT mg.id_group, COUNT(mem.id_member) AS num_members
2438
		FROM {db_prefix}membergroups AS mg
2439
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_group = mg.id_group OR FIND_IN_SET(mg.id_group, mem.additional_groups) != 0 OR mg.id_group = mem.id_post_group)
2440
		WHERE mg.id_group IN ({array_int:group_list})
2441
		GROUP BY mg.id_group',
2442
		array(
2443
			'group_list' => $groups,
2444
			'newbie_id_group' => 4,
2445
		)
2446
	);
2447
	while ($row = $smcFunc['db_fetch_assoc']($request))
2448
	{
2449
		$context['groups'][$row['id_group']] = array(
2450
			'id' => $row['id_group'],
2451
			'name' => '',
2452
			'member_count' => $row['num_members'],
2453
		);
2454
	}
2455
	$smcFunc['db_free_result']($request);
2456
2457
	// Now get the membergroup names.
2458
	$request = $smcFunc['db_query']('', '
2459
		SELECT id_group, group_name
2460
		FROM {db_prefix}membergroups
2461
		WHERE id_group IN ({array_int:group_list})',
2462
		array(
2463
			'group_list' => $groups,
2464
		)
2465
	);
2466
	while ($row = $smcFunc['db_fetch_assoc']($request))
2467
		$context['groups'][$row['id_group']]['name'] = $row['group_name'];
2468
	$smcFunc['db_free_result']($request);
2469
2470
	// Get the subject of the topic we're about to announce.
2471
	$request = $smcFunc['db_query']('', '
2472
		SELECT m.subject
2473
		FROM {db_prefix}topics AS t
2474
			INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
2475
		WHERE t.id_topic = {int:current_topic}',
2476
		array(
2477
			'current_topic' => $topic,
2478
		)
2479
	);
2480
	list ($context['topic_subject']) = $smcFunc['db_fetch_row']($request);
2481
	$smcFunc['db_free_result']($request);
2482
2483
	censorText($context['announce_topic']['subject']);
2484
2485
	$context['move'] = isset($_REQUEST['move']) ? 1 : 0;
2486
	$context['go_back'] = isset($_REQUEST['goback']) ? 1 : 0;
2487
2488
	$context['sub_template'] = 'announce';
2489
}
2490
2491
/**
2492
 * Send the announcement in chunks.
2493
 *
2494
 * splits the members to be sent a topic announcement into chunks.
2495
 * composes notification messages in all languages needed.
2496
 * does the actual sending of the topic announcements in chunks.
2497
 * calculates a rough estimate of the percentage items sent.
2498
 */
2499
function AnnouncementSend()
2500
{
2501
	global $topic, $board, $board_info, $context, $modSettings;
2502
	global $language, $scripturl, $sourcedir, $smcFunc;
2503
2504
	checkSession();
2505
2506
	$context['start'] = empty($_REQUEST['start']) ? 0 : (int) $_REQUEST['start'];
2507
	$groups = array_merge($board_info['groups'], array(1));
2508
2509
	if (isset($_POST['membergroups']))
2510
		$_POST['who'] = explode(',', $_POST['membergroups']);
2511
2512
	// Check whether at least one membergroup was selected.
2513
	if (empty($_POST['who']))
2514
		fatal_lang_error('no_membergroup_selected');
2515
2516
	// Make sure all membergroups are integers and can access the board of the announcement.
2517
	foreach ($_POST['who'] as $id => $mg)
2518
		$_POST['who'][$id] = in_array((int) $mg, $groups) ? (int) $mg : 0;
2519
2520
	// Get the topic subject and censor it.
2521
	$request = $smcFunc['db_query']('', '
2522
		SELECT m.id_msg, m.subject, m.body
2523
		FROM {db_prefix}topics AS t
2524
			INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
2525
		WHERE t.id_topic = {int:current_topic}',
2526
		array(
2527
			'current_topic' => $topic,
2528
		)
2529
	);
2530
	list ($id_msg, $context['topic_subject'], $message) = $smcFunc['db_fetch_row']($request);
2531
	$smcFunc['db_free_result']($request);
2532
2533
	censorText($context['topic_subject']);
2534
	censorText($message);
2535
2536
	$message = trim(un_htmlspecialchars(strip_tags(strtr(parse_bbc($message, false, $id_msg), array('<br>' => "\n", '</div>' => "\n", '</li>' => "\n", '&#91;' => '[', '&#93;' => ']')))));
2537
2538
	// We need this in order to be able send emails.
2539
	require_once($sourcedir . '/Subs-Post.php');
2540
2541
	// Select the email addresses for this batch.
2542
	$request = $smcFunc['db_query']('', '
2543
		SELECT mem.id_member, mem.email_address, mem.lngfile
2544
		FROM {db_prefix}members AS mem
2545
		WHERE (mem.id_group IN ({array_int:group_list}) OR mem.id_post_group IN ({array_int:group_list}) OR FIND_IN_SET({raw:additional_group_list}, mem.additional_groups) != 0)
2546
			AND mem.is_activated = {int:is_activated}
2547
			AND mem.id_member > {int:start}
2548
		ORDER BY mem.id_member
2549
		LIMIT {int:chunk_size}',
2550
		array(
2551
			'group_list' => $_POST['who'],
2552
			'is_activated' => 1,
2553
			'start' => $context['start'],
2554
			'additional_group_list' => implode(', mem.additional_groups) != 0 OR FIND_IN_SET(', $_POST['who']),
2555
			// @todo Might need an interface?
2556
			'chunk_size' => 500,
2557
		)
2558
	);
2559
2560
	// All members have received a mail. Go to the next screen.
2561
	if ($smcFunc['db_num_rows']($request) == 0)
2562
	{
2563
		logAction('announce_topic', array('topic' => $topic), 'user');
2564
		if (!empty($_REQUEST['move']) && allowedTo('move_any'))
2565
			redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
2566
		elseif (!empty($_REQUEST['goback']))
2567
			redirectexit('topic=' . $topic . '.new;boardseen#new', isBrowser('ie'));
2568
		else
2569
			redirectexit('board=' . $board . '.0');
2570
	}
2571
2572
	$announcements = array();
2573
	// Loop through all members that'll receive an announcement in this batch.
2574
	$rows = array();
2575
	while ($row = $smcFunc['db_fetch_assoc']($request))
2576
	{
2577
		$rows[$row['id_member']] = $row;
2578
	}
2579
	$smcFunc['db_free_result']($request);
2580
2581
	// Load their alert preferences
2582
	require_once($sourcedir . '/Subs-Notify.php');
2583
	$prefs = getNotifyPrefs(array_keys($rows), 'announcements', true);
2584
2585
	foreach ($rows as $row)
2586
	{
2587
		// Force them to have it?
2588
		if (empty($prefs[$row['id_member']]['announcements']))
2589
			continue;
2590
2591
		$cur_language = empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'];
2592
2593
		// If the language wasn't defined yet, load it and compose a notification message.
2594
		if (!isset($announcements[$cur_language]))
2595
		{
2596
			$replacements = array(
2597
				'TOPICSUBJECT' => $context['topic_subject'],
2598
				'MESSAGE' => $message,
2599
				'TOPICLINK' => $scripturl . '?topic=' . $topic . '.0',
2600
			);
2601
2602
			$emaildata = loadEmailTemplate('new_announcement', $replacements, $cur_language);
2603
2604
			$announcements[$cur_language] = array(
2605
				'subject' => $emaildata['subject'],
2606
				'body' => $emaildata['body'],
2607
				'is_html' => $emaildata['is_html'],
2608
				'recipients' => array(),
2609
			);
2610
		}
2611
2612
		$announcements[$cur_language]['recipients'][$row['id_member']] = $row['email_address'];
2613
		$context['start'] = $row['id_member'];
2614
	}
2615
2616
	// For each language send a different mail - low priority...
2617
	foreach ($announcements as $lang => $mail)
2618
		sendmail($mail['recipients'], $mail['subject'], $mail['body'], null, 'ann-' . $lang, $mail['is_html'], 5);
2619
2620
	$context['percentage_done'] = round(100 * $context['start'] / $modSettings['latestMember'], 1);
2621
2622
	$context['move'] = empty($_REQUEST['move']) ? 0 : 1;
2623
	$context['go_back'] = empty($_REQUEST['goback']) ? 0 : 1;
2624
	$context['membergroups'] = implode(',', $_POST['who']);
2625
	$context['sub_template'] = 'announcement_send';
2626
2627
	// Go back to the correct language for the user ;).
2628
	if (!empty($modSettings['userLanguage']))
2629
		loadLanguage('Post');
2630
}
2631
2632
/**
2633
 * Get the topic for display purposes.
2634
 *
2635
 * gets a summary of the most recent posts in a topic.
2636
 * depends on the topicSummaryPosts setting.
2637
 * if you are editing a post, only shows posts previous to that post.
2638
 */
2639
function getTopic()
2640
{
2641
	global $topic, $modSettings, $context, $smcFunc, $counter, $options;
2642
2643
	if (isset($_REQUEST['xml']))
2644
		$limit = '
2645
		LIMIT ' . (empty($context['new_replies']) ? '0' : $context['new_replies']);
2646
	else
2647
		$limit = empty($modSettings['topicSummaryPosts']) ? '' : '
2648
		LIMIT ' . (int) $modSettings['topicSummaryPosts'];
2649
2650
	// If you're modifying, get only those posts before the current one. (otherwise get all.)
2651
	$request = $smcFunc['db_query']('', '
2652
		SELECT
2653
			COALESCE(mem.real_name, m.poster_name) AS poster_name, m.poster_time,
2654
			m.body, m.smileys_enabled, m.id_msg, m.id_member
2655
		FROM {db_prefix}messages AS m
2656
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
2657
		WHERE m.id_topic = {int:current_topic}' . (isset($_REQUEST['msg']) ? '
2658
			AND m.id_msg < {int:id_msg}' : '') . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
2659
			AND m.approved = {int:approved}') . '
2660
		ORDER BY m.id_msg DESC' . $limit,
2661
		array(
2662
			'current_topic' => $topic,
2663
			'id_msg' => isset($_REQUEST['msg']) ? (int) $_REQUEST['msg'] : 0,
2664
			'approved' => 1,
2665
		)
2666
	);
2667
	$context['previous_posts'] = array();
2668
	while ($row = $smcFunc['db_fetch_assoc']($request))
2669
	{
2670
		// Censor, BBC, ...
2671
		censorText($row['body']);
2672
		$row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']);
2673
2674
		// ...and store.
2675
		$context['previous_posts'][] = array(
2676
			'counter' => $counter++,
2677
			'poster' => $row['poster_name'],
2678
			'message' => $row['body'],
2679
			'time' => timeformat($row['poster_time']),
2680
			'timestamp' => forum_time(true, $row['poster_time']),
2681
			'id' => $row['id_msg'],
2682
			'is_new' => !empty($context['new_replies']),
2683
			'is_ignored' => !empty($modSettings['enable_buddylist']) && !empty($options['posts_apply_ignore_list']) && in_array($row['id_member'], $context['user']['ignoreusers']),
2684
		);
2685
2686
		if (!empty($context['new_replies']))
2687
			$context['new_replies']--;
2688
	}
2689
	$smcFunc['db_free_result']($request);
2690
}
2691
2692
/**
2693
 * Loads a post an inserts it into the current editing text box.
2694
 * uses the Post language file.
2695
 * uses special (sadly browser dependent) javascript to parse entities for internationalization reasons.
2696
 * accessed with ?action=quotefast.
2697
 */
2698
function QuoteFast()
2699
{
2700
	global $modSettings, $user_info, $context;
2701
	global $sourcedir, $smcFunc;
2702
2703
	loadLanguage('Post');
2704
	if (!isset($_REQUEST['xml']))
2705
		loadTemplate('Post');
2706
2707
	include_once($sourcedir . '/Subs-Post.php');
2708
2709
	$moderate_boards = boardsAllowedTo('moderate_board');
2710
2711
	// Where we going if we need to?
2712
	$context['post_box_name'] = isset($_GET['pb']) ? $_GET['pb'] : '';
2713
2714
	$request = $smcFunc['db_query']('', '
2715
		SELECT COALESCE(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.body, m.id_topic, m.subject,
2716
			m.id_board, m.id_member, m.approved, m.modified_time, m.modified_name, m.modified_reason
2717
		FROM {db_prefix}messages AS m
2718
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
2719
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND {query_see_board})
2720
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
2721
		WHERE m.id_msg = {int:id_msg}' . (isset($_REQUEST['modify']) || (!empty($moderate_boards) && $moderate_boards[0] == 0) ? '' : '
2722
			AND (t.locked = {int:not_locked}' . (empty($moderate_boards) ? '' : ' OR b.id_board IN ({array_int:moderation_board_list})') . ')') . '
2723
		LIMIT 1',
2724
		array(
2725
			'current_member' => $user_info['id'],
2726
			'moderation_board_list' => $moderate_boards,
2727
			'id_msg' => (int) $_REQUEST['quote'],
2728
			'not_locked' => 0,
2729
		)
2730
	);
2731
	$context['close_window'] = $smcFunc['db_num_rows']($request) == 0;
2732
	$row = $smcFunc['db_fetch_assoc']($request);
2733
	$smcFunc['db_free_result']($request);
2734
2735
	$context['sub_template'] = 'quotefast';
2736
	if (!empty($row))
2737
		$can_view_post = $row['approved'] || ($row['id_member'] != 0 && $row['id_member'] == $user_info['id']) || allowedTo('approve_posts', $row['id_board']);
2738
2739
	if (!empty($can_view_post))
2740
	{
2741
		// Remove special formatting we don't want anymore.
2742
		$row['body'] = un_preparsecode($row['body']);
2743
2744
		// Censor the message!
2745
		censorText($row['body']);
2746
2747
		$row['body'] = preg_replace('~<br ?/?' . '>~i', "\n", $row['body']);
2748
2749
		// Want to modify a single message by double clicking it?
2750
		if (isset($_REQUEST['modify']))
2751
		{
2752
			censorText($row['subject']);
2753
2754
			$context['sub_template'] = 'modifyfast';
2755
			$context['message'] = array(
2756
				'id' => $_REQUEST['quote'],
2757
				'body' => $row['body'],
2758
				'subject' => addcslashes($row['subject'], '"'),
2759
				'reason' => array(
2760
					'name' => $row['modified_name'],
2761
					'text' => $row['modified_reason'],
2762
					'time' => $row['modified_time'],
2763
				),
2764
			);
2765
2766
			return;
2767
		}
2768
2769
		// Remove any nested quotes.
2770
		if (!empty($modSettings['removeNestedQuotes']))
2771
			$row['body'] = preg_replace(array('~\n?\[quote.*?\].+?\[/quote\]\n?~is', '~^\n~', '~\[/quote\]~'), '', $row['body']);
2772
2773
		$lb = "\n";
2774
2775
		// Add a quote string on the front and end.
2776
		$context['quote']['xml'] = '[quote author=' . $row['poster_name'] . ' link=msg=' . (int) $_REQUEST['quote'] . ' date=' . $row['poster_time'] . ']' . $lb . $row['body'] . $lb . '[/quote]';
2777
		$context['quote']['text'] = strtr(un_htmlspecialchars($context['quote']['xml']), array('\'' => '\\\'', '\\' => '\\\\', "\n" => '\\n', '</script>' => '</\' + \'script>'));
2778
		$context['quote']['xml'] = strtr($context['quote']['xml'], array('&nbsp;' => '&#160;', '<' => '&lt;', '>' => '&gt;'));
2779
2780
		$context['quote']['mozilla'] = strtr($smcFunc['htmlspecialchars']($context['quote']['text']), array('&quot;' => '"'));
2781
	}
2782
	//@todo Needs a nicer interface.
2783
	// In case our message has been removed in the meantime.
2784
	elseif (isset($_REQUEST['modify']))
2785
	{
2786
		$context['sub_template'] = 'modifyfast';
2787
		$context['message'] = array(
2788
			'id' => 0,
2789
			'body' => '',
2790
			'subject' => '',
2791
			'reason' => array(
2792
				'name' => '',
2793
				'text' => '',
2794
				'time' => '',
2795
			),
2796
		);
2797
	}
2798
	else
2799
		$context['quote'] = array(
2800
			'xml' => '',
2801
			'mozilla' => '',
2802
			'text' => '',
2803
		);
2804
}
2805
2806
/**
2807
 * Used to edit the body or subject of a message inline
2808
 * called from action=jsmodify from script and topic js
2809
 */
2810
function JavaScriptModify()
2811
{
2812
	global $sourcedir, $modSettings, $board, $topic, $txt;
2813
	global $user_info, $context, $smcFunc, $language, $board_info;
2814
2815
	// We have to have a topic!
2816
	if (empty($topic))
2817
		obExit(false);
2818
2819
	checkSession('get');
2820
	require_once($sourcedir . '/Subs-Post.php');
2821
2822
	// Assume the first message if no message ID was given.
2823
	$request = $smcFunc['db_query']('', '
2824
		SELECT
2825
			t.locked, t.num_replies, t.id_member_started, t.id_first_msg,
2826
			m.id_msg, m.id_member, m.poster_time, m.subject, m.smileys_enabled, m.body, m.icon,
2827
			m.modified_time, m.modified_name, m.modified_reason, m.approved,
2828
			m.poster_name, m.poster_email
2829
		FROM {db_prefix}messages AS m
2830
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
2831
		WHERE m.id_msg = {raw:id_msg}
2832
			AND m.id_topic = {int:current_topic}' . (allowedTo('modify_any') || allowedTo('approve_posts') ? '' : (!$modSettings['postmod_active'] ? '
2833
			AND (m.id_member != {int:guest_id} AND m.id_member = {int:current_member})' : '
2834
			AND (m.approved = {int:is_approved} OR (m.id_member != {int:guest_id} AND m.id_member = {int:current_member}))')),
2835
		array(
2836
			'current_member' => $user_info['id'],
2837
			'current_topic' => $topic,
2838
			'id_msg' => empty($_REQUEST['msg']) ? 't.id_first_msg' : (int) $_REQUEST['msg'],
2839
			'is_approved' => 1,
2840
			'guest_id' => 0,
2841
		)
2842
	);
2843
	if ($smcFunc['db_num_rows']($request) == 0)
2844
		fatal_lang_error('no_board', false);
2845
	$row = $smcFunc['db_fetch_assoc']($request);
2846
	$smcFunc['db_free_result']($request);
2847
2848
	// Change either body or subject requires permissions to modify messages.
2849
	if (isset($_POST['message']) || isset($_POST['subject']) || isset($_REQUEST['icon']))
2850
	{
2851
		if (!empty($row['locked']))
2852
			isAllowedTo('moderate_board');
2853
2854
		if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
2855
		{
2856
			if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
2857
				fatal_lang_error('modify_post_time_passed', false);
2858
			elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_own'))
2859
				isAllowedTo('modify_replies');
2860
			else
2861
				isAllowedTo('modify_own');
2862
		}
2863
		// Otherwise, they're locked out; someone who can modify the replies is needed.
2864
		elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_any'))
2865
			isAllowedTo('modify_replies');
2866
		else
2867
			isAllowedTo('modify_any');
2868
2869
		// Only log this action if it wasn't your message.
2870
		$moderationAction = $row['id_member'] != $user_info['id'];
2871
	}
2872
2873
	$post_errors = array();
2874
	if (isset($_POST['subject']) && $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['subject'])) !== '')
2875
	{
2876
		$_POST['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
2877
2878
		// Maximum number of characters.
2879
		if ($smcFunc['strlen']($_POST['subject']) > 100)
2880
			$_POST['subject'] = $smcFunc['substr']($_POST['subject'], 0, 100);
2881
	}
2882
	elseif (isset($_POST['subject']))
2883
	{
2884
		$post_errors[] = 'no_subject';
2885
		unset($_POST['subject']);
2886
	}
2887
2888
	if (isset($_POST['message']))
2889
	{
2890
		if ($smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['message'])) === '')
2891
		{
2892
			$post_errors[] = 'no_message';
2893
			unset($_POST['message']);
2894
		}
2895
		elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_POST['message']) > $modSettings['max_messageLength'])
2896
		{
2897
			$post_errors[] = 'long_message';
2898
			unset($_POST['message']);
2899
		}
2900
		else
2901
		{
2902
			$_POST['message'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
2903
2904
			preparsecode($_POST['message']);
2905
2906
			if ($smcFunc['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), implode('', $context['allowed_html_tags']))) === '')
2907
			{
2908
				$post_errors[] = 'no_message';
2909
				unset($_POST['message']);
2910
			}
2911
		}
2912
	}
2913
2914
	if (isset($_POST['lock']))
2915
	{
2916
		if (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $row['id_member']))
2917
			unset($_POST['lock']);
2918
		elseif (!allowedTo('lock_any'))
2919
		{
2920
			if ($row['locked'] == 1)
2921
				unset($_POST['lock']);
2922
			else
2923
				$_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
2924
		}
2925
		elseif (!empty($row['locked']) && !empty($_POST['lock']) || $_POST['lock'] == $row['locked'])
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (! empty($row['locked'])...ock'] == $row['locked'], Probably Intended Meaning: ! empty($row['locked']) ...ck'] == $row['locked'])
Loading history...
2926
			unset($_POST['lock']);
2927
		else
2928
			$_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
2929
	}
2930
2931
	if (isset($_POST['sticky']) && !allowedTo('make_sticky'))
2932
		unset($_POST['sticky']);
2933
2934
	if (isset($_POST['modify_reason']))
2935
	{
2936
		$_POST['modify_reason'] = strtr($smcFunc['htmlspecialchars']($_POST['modify_reason']), array("\r" => '', "\n" => '', "\t" => ''));
2937
2938
		// Maximum number of characters.
2939
		if ($smcFunc['strlen']($_POST['modify_reason']) > 100)
2940
			$_POST['modify_reason'] = $smcFunc['substr']($_POST['modify_reason'], 0, 100);
2941
	}
2942
2943
	if (empty($post_errors))
2944
	{
2945
		$msgOptions = array(
2946
			'id' => $row['id_msg'],
2947
			'subject' => isset($_POST['subject']) ? $_POST['subject'] : null,
2948
			'body' => isset($_POST['message']) ? $_POST['message'] : null,
2949
			'icon' => isset($_REQUEST['icon']) ? preg_replace('~[\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : null,
2950
			'modify_reason' => (isset($_POST['modify_reason']) ? $_POST['modify_reason'] : ''),
2951
		);
2952
		$topicOptions = array(
2953
			'id' => $topic,
2954
			'board' => $board,
2955
			'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null,
2956
			'sticky_mode' => isset($_POST['sticky']) ? (int) $_POST['sticky'] : null,
2957
			'mark_as_read' => true,
2958
		);
2959
		$posterOptions = array(
2960
			'id' => $user_info['id'],
2961
			'name' => $row['poster_name'],
2962
			'email' => $row['poster_email'],
2963
			'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count'],
2964
		);
2965
2966
		// Only consider marking as editing if they have edited the subject, message or icon.
2967
		if ((isset($_POST['subject']) && $_POST['subject'] != $row['subject']) || (isset($_POST['message']) && $_POST['message'] != $row['body']) || (isset($_REQUEST['icon']) && $_REQUEST['icon'] != $row['icon']))
2968
		{
2969
			// And even then only if the time has passed...
2970
			if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member'])
2971
			{
2972
				$msgOptions['modify_time'] = time();
2973
				$msgOptions['modify_name'] = $user_info['name'];
2974
			}
2975
		}
2976
		// If nothing was changed there's no need to add an entry to the moderation log.
2977
		else
2978
			$moderationAction = false;
2979
2980
		modifyPost($msgOptions, $topicOptions, $posterOptions);
2981
2982
		// If we didn't change anything this time but had before put back the old info.
2983
		if (!isset($msgOptions['modify_time']) && !empty($row['modified_time']))
2984
		{
2985
			$msgOptions['modify_time'] = $row['modified_time'];
2986
			$msgOptions['modify_name'] = $row['modified_name'];
2987
			$msgOptions['modify_reason'] = $row['modified_reason'];
2988
		}
2989
2990
		// Changing the first subject updates other subjects to 'Re: new_subject'.
2991
		if (isset($_POST['subject']) && isset($_REQUEST['change_all_subjects']) && $row['id_first_msg'] == $row['id_msg'] && !empty($row['num_replies']) && (allowedTo('modify_any') || ($row['id_member_started'] == $user_info['id'] && allowedTo('modify_replies'))))
2992
		{
2993
			// Get the proper (default language) response prefix first.
2994
			if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix')))
2995
			{
2996
				if ($language === $user_info['language'])
2997
					$context['response_prefix'] = $txt['response_prefix'];
2998
				else
2999
				{
3000
					loadLanguage('index', $language, false);
3001
					$context['response_prefix'] = $txt['response_prefix'];
3002
					loadLanguage('index');
3003
				}
3004
				cache_put_data('response_prefix', $context['response_prefix'], 600);
3005
			}
3006
3007
			$smcFunc['db_query']('', '
3008
				UPDATE {db_prefix}messages
3009
				SET subject = {string:subject}
3010
				WHERE id_topic = {int:current_topic}
3011
					AND id_msg != {int:id_first_msg}',
3012
				array(
3013
					'current_topic' => $topic,
3014
					'id_first_msg' => $row['id_first_msg'],
3015
					'subject' => $context['response_prefix'] . $_POST['subject'],
3016
				)
3017
			);
3018
		}
3019
3020
		if (!empty($moderationAction))
3021
			logAction('modify', array('topic' => $topic, 'message' => $row['id_msg'], 'member' => $row['id_member'], 'board' => $board));
3022
	}
3023
3024
	if (isset($_REQUEST['xml']))
3025
	{
3026
		$context['sub_template'] = 'modifydone';
3027
		if (empty($post_errors) && isset($msgOptions['subject']) && isset($msgOptions['body']))
3028
		{
3029
			$context['message'] = array(
3030
				'id' => $row['id_msg'],
3031
				'modified' => array(
3032
					'time' => isset($msgOptions['modify_time']) ? timeformat($msgOptions['modify_time']) : '',
3033
					'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0,
3034
					'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : '',
3035
					'reason' => $msgOptions['modify_reason'],
3036
				),
3037
				'subject' => $msgOptions['subject'],
3038
				'first_in_topic' => $row['id_msg'] == $row['id_first_msg'],
3039
				'body' => strtr($msgOptions['body'], array(']]>' => ']]]]><![CDATA[>')),
3040
			);
3041
3042
			censorText($context['message']['subject']);
3043
			censorText($context['message']['body']);
3044
3045
			$context['message']['body'] = parse_bbc($context['message']['body'], $row['smileys_enabled'], $row['id_msg']);
3046
		}
3047
		// Topic?
3048
		elseif (empty($post_errors))
3049
		{
3050
			$context['sub_template'] = 'modifytopicdone';
3051
			$context['message'] = array(
3052
				'id' => $row['id_msg'],
3053
				'modified' => array(
3054
					'time' => isset($msgOptions['modify_time']) ? timeformat($msgOptions['modify_time']) : '',
3055
					'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0,
3056
					'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : '',
3057
				),
3058
				'subject' => isset($msgOptions['subject']) ? $msgOptions['subject'] : '',
3059
			);
3060
3061
			censorText($context['message']['subject']);
3062
		}
3063
		else
3064
		{
3065
			$context['message'] = array(
3066
				'id' => $row['id_msg'],
3067
				'errors' => array(),
3068
				'error_in_subject' => in_array('no_subject', $post_errors),
3069
				'error_in_body' => in_array('no_message', $post_errors) || in_array('long_message', $post_errors),
3070
			);
3071
3072
			loadLanguage('Errors');
3073
			foreach ($post_errors as $post_error)
3074
			{
3075
				if ($post_error == 'long_message')
3076
					$context['message']['errors'][] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']);
3077
				else
3078
					$context['message']['errors'][] = $txt['error_' . $post_error];
3079
			}
3080
		}
3081
	}
3082
	else
3083
		obExit(false);
3084
}
3085
3086
?>