getTopic()   C
last analyzed

Complexity

Conditions 12

Size

Total Lines 51
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 32
nop 0
dl 0
loc 51
rs 6.9666
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 2019 Simple Machines and individual contributors
12
 * @license http://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1 RC2
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
		);
106
		if ($smcFunc['db_num_rows']($request) != 1)
107
			unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
108
		else
109
			list ($topic) = $smcFunc['db_fetch_row']($request);
110
		$smcFunc['db_free_result']($request);
111
	}
112
113
	// Check if it's locked. It isn't locked if no topic is specified.
114
	if (!empty($topic))
115
	{
116
		$request = $smcFunc['db_query']('', '
117
			SELECT
118
				t.locked, t.approved, COALESCE(ln.id_topic, 0) AS notify, t.is_sticky, t.id_poll, t.id_last_msg, mf.id_member,
119
				t.id_first_msg, mf.subject, ml.modified_reason,
120
				CASE WHEN ml.poster_time > ml.modified_time THEN ml.poster_time ELSE ml.modified_time END AS last_post_time
121
			FROM {db_prefix}topics AS t
122
				LEFT JOIN {db_prefix}log_notify AS ln ON (ln.id_topic = t.id_topic AND ln.id_member = {int:current_member})
123
				LEFT JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)
124
				LEFT JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
125
			WHERE t.id_topic = {int:current_topic}
126
			LIMIT 1',
127
			array(
128
				'current_member' => $user_info['id'],
129
				'current_topic' => $topic,
130
			)
131
		);
132
		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);
133
		$smcFunc['db_free_result']($request);
134
135
		// If this topic already has a poll, they sure can't add another.
136
		if (isset($_REQUEST['poll']) && $pollID > 0)
137
			unset($_REQUEST['poll']);
138
139
		if (empty($_REQUEST['msg']))
140
		{
141
			if ($user_info['is_guest'] && !allowedTo('post_reply_any') && (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_replies_any')))
142
				is_not_guest();
143
144
			// By default the reply will be approved...
145
			$context['becomes_approved'] = true;
146
			if ($id_member_poster != $user_info['id'] || $user_info['is_guest'])
147
			{
148
				if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any'))
149
					$context['becomes_approved'] = false;
150
				else
151
					isAllowedTo('post_reply_any');
152
			}
153
			elseif (!allowedTo('post_reply_any'))
154
			{
155
				if ($modSettings['postmod_active'] && ((allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) || allowedTo('post_unapproved_replies_any')))
156
					$context['becomes_approved'] = false;
157
				else
158
					isAllowedTo('post_reply_own');
159
			}
160
		}
161
		else
162
			$context['becomes_approved'] = true;
163
164
		$context['can_lock'] = allowedTo('lock_any') || ($user_info['id'] == $id_member_poster && allowedTo('lock_own'));
165
		$context['can_sticky'] = allowedTo('make_sticky');
166
		$context['can_move'] = allowedTo('move_any');
167
		// You can only announce topics that will get approved...
168
		$context['can_announce'] = allowedTo('announce_topic') && $context['becomes_approved'];
169
		$context['show_approval'] = !allowedTo('approve_posts') ? 0 : ($context['becomes_approved'] ? 2 : 1);
170
171
		// We don't always want the request vars to override what's in the db...
172
		$context['already_locked'] = $locked;
173
		$context['already_sticky'] = $sticky;
174
		$context['sticky'] = isset($_REQUEST['sticky']) ? !empty($_REQUEST['sticky']) : $sticky;
175
176
		// Check whether this is a really old post being bumped...
177
		if (!empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky) && !isset($_REQUEST['subject']))
178
			$post_errors[] = array('old_topic', array($modSettings['oldTopicDays']));
179
	}
180
	else
181
	{
182
		// @todo Should use JavaScript to hide and show the warning based on the selection in the board select menu
183
		$context['becomes_approved'] = true;
184
		if ($modSettings['postmod_active'] && !allowedTo('post_new', $boards, true) && allowedTo('post_unapproved_topics', $boards, true))
185
			$context['becomes_approved'] = false;
186
		else
187
			isAllowedTo('post_new', $boards, true);
188
189
		$locked = 0;
190
		$context['already_locked'] = 0;
191
		$context['already_sticky'] = 0;
192
		$context['sticky'] = !empty($_REQUEST['sticky']);
193
194
		// What options should we show?
195
		$context['can_lock'] = allowedTo(array('lock_any', 'lock_own'), $boards, true);
196
		$context['can_sticky'] = allowedTo('make_sticky', $boards, true);
197
		$context['can_move'] = allowedTo('move_any', $boards, true);
198
		$context['can_announce'] = allowedTo('announce_topic', $boards, true) && $context['becomes_approved'];
199
		$context['show_approval'] = !allowedTo('approve_posts', $boards, true) ? 0 : ($context['becomes_approved'] ? 2 : 1);
200
	}
201
202
	$context['notify'] = !empty($context['notify']);
203
204
	$context['can_notify'] = !$context['user']['is_guest'];
205
	$context['move'] = !empty($_REQUEST['move']);
206
	$context['announce'] = !empty($_REQUEST['announce']);
207
	$context['locked'] = !empty($locked) || !empty($_REQUEST['lock']);
208
	$context['can_quote'] = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC']));
209
210
	// An array to hold all the attachments for this topic.
211
	$context['current_attachments'] = array();
212
213
	// Clear out prior attachment activity when starting afresh
214
	if (empty($_REQUEST['message']) && empty($_REQUEST['preview']) && !empty($_SESSION['already_attached']))
215
	{
216
		require_once($sourcedir . '/ManageAttachments.php');
217
		foreach ($_SESSION['already_attached'] as $attachID => $attachment)
218
			removeAttachments(array('id_attach' => $attachID));
219
220
		unset($_SESSION['already_attached']);
221
	}
222
223
	// Don't allow a post if it's locked and you aren't all powerful.
224
	if ($locked && !allowedTo('moderate_board'))
225
		fatal_lang_error('topic_locked', false);
226
	// Check the users permissions - is the user allowed to add or post a poll?
227
	if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1')
228
	{
229
		// New topic, new poll.
230
		if (empty($topic))
231
			isAllowedTo('poll_post');
232
		// This is an old topic - but it is yours!  Can you add to it?
233
		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...
234
			isAllowedTo('poll_add_own');
235
		// If you're not the owner, can you add to any poll?
236
		else
237
			isAllowedTo('poll_add_any');
238
239
		if (!empty($board))
240
		{
241
			require_once($sourcedir . '/Subs-Members.php');
242
			$allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
243
			$guest_vote_enabled = in_array(-1, $allowedVoteGroups['allowed']);
244
		}
245
		// No board, so we'll have to check this again in Post2
246
		else
247
			$guest_vote_enabled = true;
248
249
		// Set up the poll options.
250
		$context['poll_options'] = array(
251
			'max_votes' => empty($_POST['poll_max_votes']) ? '1' : max(1, $_POST['poll_max_votes']),
252
			'hide' => empty($_POST['poll_hide']) ? 0 : $_POST['poll_hide'],
253
			'expire' => !isset($_POST['poll_expire']) ? '' : $_POST['poll_expire'],
254
			'change_vote' => isset($_POST['poll_change_vote']),
255
			'guest_vote' => isset($_POST['poll_guest_vote']),
256
			'guest_vote_enabled' => $guest_vote_enabled,
257
		);
258
259
		// Make all five poll choices empty.
260
		$context['choices'] = array(
261
			array('id' => 0, 'number' => 1, 'label' => '', 'is_last' => false),
262
			array('id' => 1, 'number' => 2, 'label' => '', 'is_last' => false),
263
			array('id' => 2, 'number' => 3, 'label' => '', 'is_last' => false),
264
			array('id' => 3, 'number' => 4, 'label' => '', 'is_last' => false),
265
			array('id' => 4, 'number' => 5, 'label' => '', 'is_last' => true)
266
		);
267
		$context['last_choice_id'] = 4;
268
	}
269
270
	if ($context['make_event'])
271
	{
272
		// They might want to pick a board.
273
		if (!isset($context['current_board']))
274
			$context['current_board'] = 0;
275
276
		// Start loading up the event info.
277
		$context['event'] = array();
278
		$context['event']['title'] = isset($_REQUEST['evtitle']) ? $smcFunc['htmlspecialchars'](stripslashes($_REQUEST['evtitle'])) : '';
279
		$context['event']['location'] = isset($_REQUEST['event_location']) ? $smcFunc['htmlspecialchars'](stripslashes($_REQUEST['event_location'])) : '';
280
281
		$context['event']['id'] = isset($_REQUEST['eventid']) ? (int) $_REQUEST['eventid'] : -1;
282
		$context['event']['new'] = $context['event']['id'] == -1;
283
284
		// Permissions check!
285
		isAllowedTo('calendar_post');
286
287
		require_once($sourcedir . '/Subs-Calendar.php');
288
289
		// We want a fairly compact version of the time, but as close as possible to the user's settings.
290
		$time_string = strtr(get_date_or_time_format('time'), array(
291
			'%I' => '%l',
292
			'%H' => '%k',
293
			'%S' => '',
294
			'%r' => '%l:%M %p',
295
			'%R' => '%k:%M',
296
			'%T' => '%l:%M',
297
		));
298
299
		// Editing an event?  (but NOT previewing!?)
300
		if (empty($context['event']['new']) && !isset($_REQUEST['subject']))
301
		{
302
			// If the user doesn't have permission to edit the post in this topic, redirect them.
303
			if ((empty($id_member_poster) || $id_member_poster != $user_info['id'] || !allowedTo('modify_own')) && !allowedTo('modify_any'))
304
			{
305
				require_once($sourcedir . '/Calendar.php');
306
				return CalendarPost();
0 ignored issues
show
Bug introduced by
Are you sure the usage of CalendarPost() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
307
			}
308
309
			// Get the current event information.
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
			$eventProperties = getNewEventDatetimes();
317
			$context['event'] = array_merge($context['event'], $eventProperties);
318
319
			// Make sure the year and month are in the valid range.
320
			if ($context['event']['month'] < 1 || $context['event']['month'] > 12)
321
				fatal_lang_error('invalid_month', false);
322
			if ($context['event']['year'] < $modSettings['cal_minyear'] || $context['event']['year'] > $modSettings['cal_maxyear'])
323
				fatal_lang_error('invalid_year', false);
324
325
			$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...
326
		}
327
328
		// Find the last day of the month.
329
		$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']));
330
331
		// An all day event? Set up some nice defaults in case the user wants to change that
332
		if ($context['event']['allday'] == true)
333
		{
334
			$context['event']['tz'] = getUserTimezone();
335
			$context['event']['start_time'] = timeformat(time(), $time_string);
0 ignored issues
show
Bug introduced by
$time_string of type string is incompatible with the type boolean expected by parameter $show_today of timeformat(). ( Ignorable by Annotation )

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

335
			$context['event']['start_time'] = timeformat(time(), /** @scrutinizer ignore-type */ $time_string);
Loading history...
336
			$context['event']['end_time'] = timeformat(time() + 3600, $time_string);
337
		}
338
		// Otherwise, just adjust these to look nice on the input form
339
		else
340
		{
341
			$context['event']['start_time'] = $context['event']['start_time_orig'];
342
			$context['event']['end_time'] = $context['event']['end_time_orig'];
343
		}
344
345
		// Need this so the user can select a timezone for the event.
346
		$context['all_timezones'] = smf_list_timezones($context['event']['start_date']);
347
		unset($context['all_timezones']['']);
348
349
		// If the event's timezone is not in SMF's standard list of time zones, prepend it to the list
350
		if (!in_array($context['event']['tz'], array_keys($context['all_timezones'])))
351
		{
352
			$d = date_create($context['event']['start_datetime'] . ' ' . $context['event']['tz']);
353
			$context['all_timezones'] = array($context['event']['tz'] => '[UTC' . date_format($d, 'P') . '] - ' . $context['event']['tz']) + $context['all_timezones'];
354
		}
355
356
		loadDatePicker('#event_time_input .date_input');
357
		loadTimePicker('#event_time_input .date_input', $time_string);
358
		loadDatePair('#event_time_input', 'date_input', 'time_input');
359
		addInlineJavaScript('
360
	$("#allday").click(function(){
361
		$("#start_time").attr("disabled", this.checked);
362
		$("#end_time").attr("disabled", this.checked);
363
		$("#tz").attr("disabled", this.checked);
364
	});	', true);
365
366
		$context['event']['board'] = !empty($board) ? $board : $modSettings['cal_defaultboard'];
367
		$context['event']['topic'] = !empty($topic) ? $topic : 0;
368
	}
369
370
	// See if any new replies have come along.
371
	// Huh, $_REQUEST['msg'] is set upon submit, so this doesn't get executed at submit
372
	// only at preview
373
	if (empty($_REQUEST['msg']) && !empty($topic))
374
	{
375
		if (isset($_REQUEST['last_msg']) && $context['topic_last_message'] > $_REQUEST['last_msg'])
376
		{
377
			$request = $smcFunc['db_query']('', '
378
				SELECT COUNT(*)
379
				FROM {db_prefix}messages
380
				WHERE id_topic = {int:current_topic}
381
					AND id_msg > {int:last_msg}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
382
					AND approved = {int:approved}') . '
383
				LIMIT 1',
384
				array(
385
					'current_topic' => $topic,
386
					'last_msg' => (int) $_REQUEST['last_msg'],
387
					'approved' => 1,
388
				)
389
			);
390
			list ($context['new_replies']) = $smcFunc['db_fetch_row']($request);
391
			$smcFunc['db_free_result']($request);
392
393
			if (!empty($context['new_replies']))
394
			{
395
				if ($context['new_replies'] == 1)
396
					$txt['error_new_replies'] = isset($_GET['last_msg']) ? $txt['error_new_reply_reading'] : $txt['error_new_reply'];
397
				else
398
					$txt['error_new_replies'] = sprintf(isset($_GET['last_msg']) ? $txt['error_new_replies_reading'] : $txt['error_new_replies'], $context['new_replies']);
399
400
				$post_errors[] = 'new_replies';
401
402
				$modSettings['topicSummaryPosts'] = $context['new_replies'] > $modSettings['topicSummaryPosts'] ? max($modSettings['topicSummaryPosts'], 5) : $modSettings['topicSummaryPosts'];
403
			}
404
		}
405
	}
406
407
	// Get a response prefix (like 'Re:') in the default forum language.
408
	if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix')))
409
	{
410
		if ($language === $user_info['language'])
411
			$context['response_prefix'] = $txt['response_prefix'];
412
		else
413
		{
414
			loadLanguage('index', $language, false);
415
			$context['response_prefix'] = $txt['response_prefix'];
416
			loadLanguage('index');
417
		}
418
		cache_put_data('response_prefix', $context['response_prefix'], 600);
419
	}
420
421
	// Previewing, modifying, or posting?
422
	// Do we have a body, but an error happened.
423
	if (isset($_REQUEST['message']) || isset($_REQUEST['quickReply']) || !empty($context['post_error']))
424
	{
425
		if (isset($_REQUEST['quickReply']))
426
			$_REQUEST['message'] = $_REQUEST['quickReply'];
427
428
		// Validate inputs.
429
		if (empty($context['post_error']))
430
		{
431
			// This means they didn't click Post and get an error.
432
			$really_previewing = true;
433
		}
434
		else
435
		{
436
			if (!isset($_REQUEST['subject']))
437
				$_REQUEST['subject'] = '';
438
			if (!isset($_REQUEST['message']))
439
				$_REQUEST['message'] = '';
440
			if (!isset($_REQUEST['icon']))
441
				$_REQUEST['icon'] = 'xx';
442
443
			// They are previewing if they asked to preview (i.e. came from quick reply).
444
			$really_previewing = !empty($_POST['preview']);
445
		}
446
447
		// In order to keep the approval status flowing through, we have to pass it through the form...
448
		$context['becomes_approved'] = empty($_REQUEST['not_approved']);
449
		$context['show_approval'] = isset($_REQUEST['approve']) ? ($_REQUEST['approve'] ? 2 : 1) : allowedTo('approve_posts') ? 2 : 0;
450
		$context['can_announce'] &= $context['becomes_approved'];
451
452
		// Set up the inputs for the form.
453
		$form_subject = strtr($smcFunc['htmlspecialchars']($_REQUEST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
454
		$form_message = $smcFunc['htmlspecialchars']($_REQUEST['message'], ENT_QUOTES);
455
456
		// Make sure the subject isn't too long - taking into account special characters.
457
		if ($smcFunc['strlen']($form_subject) > 100)
458
			$form_subject = $smcFunc['substr']($form_subject, 0, 100);
459
460
		if (isset($_REQUEST['poll']))
461
		{
462
			$context['question'] = isset($_REQUEST['question']) ? $smcFunc['htmlspecialchars'](trim($_REQUEST['question'])) : '';
463
464
			$context['choices'] = array();
465
			$choice_id = 0;
466
467
			$_POST['options'] = empty($_POST['options']) ? array() : htmlspecialchars__recursive($_POST['options']);
468
			foreach ($_POST['options'] as $option)
469
			{
470
				if (trim($option) == '')
471
					continue;
472
473
				$context['choices'][] = array(
474
					'id' => $choice_id++,
475
					'number' => $choice_id,
476
					'label' => $option,
477
					'is_last' => false
478
				);
479
			}
480
481
			// One empty option for those with js disabled...I know are few... :P
482
			$context['choices'][] = array(
483
				'id' => $choice_id++,
484
				'number' => $choice_id,
485
				'label' => '',
486
				'is_last' => false
487
			);
488
489
			if (count($context['choices']) < 2)
490
			{
491
				$context['choices'][] = array(
492
					'id' => $choice_id++,
493
					'number' => $choice_id,
494
					'label' => '',
495
					'is_last' => false
496
				);
497
			}
498
			$context['last_choice_id'] = $choice_id;
499
			$context['choices'][count($context['choices']) - 1]['is_last'] = true;
500
		}
501
502
		// Are you... a guest?
503
		if ($user_info['is_guest'])
504
		{
505
			$_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']);
506
			$_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']);
507
508
			$_REQUEST['guestname'] = $smcFunc['htmlspecialchars']($_REQUEST['guestname']);
509
			$context['name'] = $_REQUEST['guestname'];
510
			$_REQUEST['email'] = $smcFunc['htmlspecialchars']($_REQUEST['email']);
511
			$context['email'] = $_REQUEST['email'];
512
513
			$user_info['name'] = $_REQUEST['guestname'];
514
		}
515
516
		// Only show the preview stuff if they hit Preview.
517
		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...
518
		{
519
			// Set up the preview message and subject and censor them...
520
			$context['preview_message'] = $form_message;
521
			preparsecode($form_message, true);
522
			preparsecode($context['preview_message']);
523
524
			// Do all bulletin board code tags, with or without smileys.
525
			$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

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

830
				for ($i = 0, $n = count(/** @scrutinizer ignore-type */ $parts); $i < $n; $i++)
Loading history...
831
				{
832
					// It goes 0 = outside, 1 = begin tag, 2 = inside, 3 = close tag, repeat.
833
					if ($i % 4 == 0)
834
						$parts[$i] = preg_replace_callback('~\[html\](.+?)\[/html\]~is', function($m)
835
						{
836
							return '[html]' . preg_replace('~<br\s?/?' . '>~i', '&lt;br /&gt;<br>', "$m[1]") . '[/html]';
837
						}, $parts[$i]);
838
				}
839
				$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

839
				$form_message = implode('', /** @scrutinizer ignore-type */ $parts);
Loading history...
840
			}
841
842
			$form_message = preg_replace('~<br ?/?' . '>~i', "\n", $form_message);
843
844
			// Remove any nested quotes, if necessary.
845
			if (!empty($modSettings['removeNestedQuotes']))
846
				$form_message = preg_replace(array('~\n?\[quote.*?\].+?\[/quote\]\n?~is', '~^\n~', '~\[/quote\]~'), '', $form_message);
847
848
			// Add a quote string on the front and end.
849
			$form_message = '[quote author=' . $mname . ' link=msg=' . (int) $_REQUEST['quote'] . ' date=' . $mdate . ']' . "\n" . rtrim($form_message) . "\n" . '[/quote]';
850
		}
851
		// Posting a reply without a quote?
852
		elseif (!empty($topic) && empty($_REQUEST['quote']))
853
		{
854
			// Get the first message's subject.
855
			$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...
856
857
			// Add 'Re: ' to the front of the subject.
858
			if (trim($context['response_prefix']) != '' && $form_subject != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0)
859
				$form_subject = $context['response_prefix'] . $form_subject;
860
861
			// Censor the subject.
862
			censorText($form_subject);
863
864
			$form_message = '';
865
		}
866
		else
867
		{
868
			$form_subject = isset($_GET['subject']) ? $_GET['subject'] : '';
869
			$form_message = '';
870
		}
871
	}
872
873
	$context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment', $boards, true) || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments', $boards, true)));
874
875
	if ($context['can_post_attachment'])
876
	{
877
		// If there are attachments, calculate the total size and how many.
878
		$context['attachments']['total_size'] = 0;
879
		$context['attachments']['quantity'] = 0;
880
881
		// If this isn't a new post, check the current attachments.
882
		if (isset($_REQUEST['msg']))
883
		{
884
			$context['attachments']['quantity'] = count($context['current_attachments']);
885
			foreach ($context['current_attachments'] as $attachment)
886
				$context['attachments']['total_size'] += $attachment['size'];
887
		}
888
889
		// A bit of house keeping first.
890
		if (!empty($_SESSION['temp_attachments']) && count($_SESSION['temp_attachments']) == 1)
891
			unset($_SESSION['temp_attachments']);
892
893
		if (!empty($_SESSION['temp_attachments']))
894
		{
895
			// Is this a request to delete them?
896
			if (isset($_GET['delete_temp']))
897
			{
898
				foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
899
				{
900
					if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false)
901
						if (file_exists($attachment['tmp_name']))
902
							unlink($attachment['tmp_name']);
903
				}
904
				$post_errors[] = 'temp_attachments_gone';
905
				$_SESSION['temp_attachments'] = array();
906
			}
907
			// Hmm, coming in fresh and there are files in session.
908
			elseif ($context['current_action'] != 'post2' || !empty($_POST['from_qr']))
909
			{
910
				// Let's be nice and see if they belong here first.
911
				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']))
912
				{
913
					// See if any files still exist before showing the warning message and the files attached.
914
					foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
915
					{
916
						if (strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
917
							continue;
918
919
						if (file_exists($attachment['tmp_name']))
920
						{
921
							$post_errors[] = 'temp_attachments_new';
922
							$context['files_in_session_warning'] = $txt['attached_files_in_session'];
923
							unset($_SESSION['temp_attachments']['post']['files']);
924
							break;
925
						}
926
					}
927
				}
928
				else
929
				{
930
					// Since, they don't belong here. Let's inform the user that they exist..
931
					if (!empty($topic))
932
						$delete_url = $scripturl . '?action=post' . (!empty($_REQUEST['msg']) ? (';msg=' . $_REQUEST['msg']) : '') . (!empty($_REQUEST['last_msg']) ? (';last_msg=' . $_REQUEST['last_msg']) : '') . ';topic=' . $topic . ';delete_temp';
933
					else
934
						$delete_url = $scripturl . '?action=post' . (!empty($board) ? ';board=' . $board : '') . ';delete_temp';
935
936
					// Compile a list of the files to show the user.
937
					$file_list = array();
938
					foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
939
						if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false)
940
							$file_list[] = $attachment['name'];
941
942
					$_SESSION['temp_attachments']['post']['files'] = $file_list;
943
					$file_list = '<div class="attachments">' . implode('<br>', $file_list) . '</div>';
944
945
					if (!empty($_SESSION['temp_attachments']['post']['msg']))
946
					{
947
						// We have a message id, so we can link back to the old topic they were trying to edit..
948
						$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';
949
950
						$post_errors[] = array('temp_attachments_found', array($delete_url, $goback_url, $file_list));
951
						$context['ignore_temp_attachments'] = true;
952
					}
953
					else
954
					{
955
						$post_errors[] = array('temp_attachments_lost', array($delete_url, $file_list));
956
						$context['ignore_temp_attachments'] = true;
957
					}
958
				}
959
			}
960
961
			if (!empty($context['we_are_history']))
962
				$post_errors[] = $context['we_are_history'];
963
964
			foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
965
			{
966
				if (isset($context['ignore_temp_attachments']) || isset($_SESSION['temp_attachments']['post']['files']))
967
					break;
968
969
				if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
970
					continue;
971
972
				if ($attachID == 'initial_error')
973
				{
974
					$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>';
975
					$post_errors[] = 'attach_initial_error';
976
					unset($_SESSION['temp_attachments']);
977
					break;
978
				}
979
980
				// Show any errors which might have occurred.
981
				if (!empty($attachment['errors']))
982
				{
983
					$txt['error_attach_errors'] = empty($txt['error_attach_errors']) ? '<br>' : '';
984
					$txt['error_attach_errors'] .= vsprintf($txt['attach_warning'], $attachment['name']) . '<div style="padding: 0 1em;">';
985
					foreach ($attachment['errors'] as $error)
986
						$txt['error_attach_errors'] .= (is_array($error) ? vsprintf($txt[$error[0]], $error[1]) : $txt[$error]) . '<br >';
987
					$txt['error_attach_errors'] .= '</div>';
988
					$post_errors[] = 'attach_errors';
989
990
					// Take out the trash.
991
					unset($_SESSION['temp_attachments'][$attachID]);
992
					if (file_exists($attachment['tmp_name']))
993
						unlink($attachment['tmp_name']);
994
					continue;
995
				}
996
997
				// More house keeping.
998
				if (!file_exists($attachment['tmp_name']))
999
				{
1000
					unset($_SESSION['temp_attachments'][$attachID]);
1001
					continue;
1002
				}
1003
1004
				$context['attachments']['quantity']++;
1005
				$context['attachments']['total_size'] += $attachment['size'];
1006
				if (!isset($context['files_in_session_warning']))
1007
					$context['files_in_session_warning'] = $txt['attached_files_in_session'];
1008
1009
				$context['current_attachments'][$attachID] = array(
1010
					'name' => $smcFunc['htmlspecialchars']($attachment['name']),
1011
					'size' => $attachment['size'],
1012
					'attachID' => $attachID,
1013
					'unchecked' => false,
1014
					'approved' => 1,
1015
					'mime_type' => '',
1016
					'thumb' => 0,
1017
				);
1018
			}
1019
		}
1020
	}
1021
1022
	// Do we need to show the visual verification image?
1023
	$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));
1024
	if ($context['require_verification'])
1025
	{
1026
		require_once($sourcedir . '/Subs-Editor.php');
1027
		$verificationOptions = array(
1028
			'id' => 'post',
1029
		);
1030
		$context['require_verification'] = create_control_verification($verificationOptions);
1031
		$context['visual_verification_id'] = $verificationOptions['id'];
1032
	}
1033
1034
	// If they came from quick reply, and have to enter verification details, give them some notice.
1035
	if (!empty($_REQUEST['from_qr']) && !empty($context['require_verification']))
1036
		$post_errors[] = 'need_qr_verification';
1037
1038
	/*
1039
	 * There are two error types: serious and minor. Serious errors
1040
	 * actually tell the user that a real error has occurred, while minor
1041
	 * errors are like warnings that let them know that something with
1042
	 * their post isn't right.
1043
	 */
1044
	$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');
1045
1046
	call_integration_hook('integrate_post_errors', array(&$post_errors, &$minor_errors));
1047
1048
	// Any errors occurred?
1049
	if (!empty($post_errors))
1050
	{
1051
		loadLanguage('Errors');
1052
		$context['error_type'] = 'minor';
1053
		foreach ($post_errors as $post_error)
1054
			if (is_array($post_error))
1055
			{
1056
				$post_error_id = $post_error[0];
1057
				$context['post_error'][$post_error_id] = vsprintf($txt['error_' . $post_error_id], $post_error[1]);
1058
1059
				// If it's not a minor error flag it as such.
1060
				if (!in_array($post_error_id, $minor_errors))
1061
					$context['error_type'] = 'serious';
1062
			}
1063
			else
1064
			{
1065
				$context['post_error'][$post_error] = $txt['error_' . $post_error];
1066
1067
				// If it's not a minor error flag it as such.
1068
				if (!in_array($post_error, $minor_errors))
1069
					$context['error_type'] = 'serious';
1070
			}
1071
	}
1072
1073
	// What are you doing? Posting a poll, modifying, previewing, new post, or reply...
1074
	if (isset($_REQUEST['poll']))
1075
		$context['page_title'] = $txt['new_poll'];
1076
	elseif ($context['make_event'])
1077
		$context['page_title'] = $context['event']['id'] == -1 ? $txt['calendar_post_event'] : $txt['calendar_edit'];
1078
	elseif (isset($_REQUEST['msg']))
1079
		$context['page_title'] = $txt['modify_msg'];
1080
	elseif (isset($_REQUEST['subject'], $context['preview_subject']))
1081
		$context['page_title'] = $txt['preview'] . ' - ' . strip_tags($context['preview_subject']);
1082
	elseif (empty($topic))
1083
		$context['page_title'] = $txt['start_new_topic'];
1084
	else
1085
		$context['page_title'] = $txt['post_reply'];
1086
1087
	// Build the link tree.
1088
	if (empty($topic))
1089
		$context['linktree'][] = array(
1090
			'name' => '<em>' . $txt['start_new_topic'] . '</em>'
1091
		);
1092
	else
1093
		$context['linktree'][] = array(
1094
			'url' => $scripturl . '?topic=' . $topic . '.' . $_REQUEST['start'],
1095
			'name' => $form_subject,
1096
			'extra_before' => '<span><strong class="nav">' . $context['page_title'] . ' (</strong></span>',
1097
			'extra_after' => '<span><strong class="nav">)</strong></span>'
1098
		);
1099
1100
	$context['subject'] = addcslashes($form_subject, '"');
1101
	$context['message'] = str_replace(array('"', '<', '>', '&nbsp;'), array('&quot;', '&lt;', '&gt;', ' '), $form_message);
1102
1103
	// Are post drafts enabled?
1104
	$context['drafts_save'] = !empty($modSettings['drafts_post_enabled']) && allowedTo('post_draft');
1105
	$context['drafts_autosave'] = !empty($context['drafts_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('post_autosave_draft');
1106
1107
	// Build a list of drafts that they can load in to the editor
1108
	if (!empty($context['drafts_save']))
1109
	{
1110
		require_once($sourcedir . '/Drafts.php');
1111
		ShowDrafts($user_info['id'], $topic);
1112
	}
1113
1114
	// Needed for the editor and message icons.
1115
	require_once($sourcedir . '/Subs-Editor.php');
1116
1117
	// Now create the editor.
1118
	$editorOptions = array(
1119
		'id' => 'message',
1120
		'value' => $context['message'],
1121
		'labels' => array(
1122
			'post_button' => $context['submit_label'],
1123
		),
1124
		// add height and width for the editor
1125
		'height' => '275px',
1126
		'width' => '100%',
1127
		// We do XML preview here.
1128
		'preview_type' => 2,
1129
		'required' => true,
1130
	);
1131
	create_control_richedit($editorOptions);
1132
1133
	// Store the ID.
1134
	$context['post_box_name'] = $editorOptions['id'];
1135
1136
	$context['attached'] = '';
1137
	$context['make_poll'] = isset($_REQUEST['poll']);
1138
1139
	// Message icons - customized icons are off?
1140
	$context['icons'] = getMessageIcons(!empty($board) ? $board : 0);
1141
1142
	if (!empty($context['icons']))
1143
		$context['icons'][count($context['icons']) - 1]['is_last'] = true;
1144
1145
	// Are we starting a poll? if set the poll icon as selected if its available
1146
	if (isset($_REQUEST['poll']))
1147
	{
1148
		foreach ($context['icons'] as $icons)
1149
		{
1150
			if (isset($icons['value']) && $icons['value'] == 'poll')
1151
			{
1152
				// if found we are done
1153
				$context['icon'] = 'poll';
1154
				break;
1155
			}
1156
		}
1157
	}
1158
1159
	$context['icon_url'] = '';
1160
	for ($i = 0, $n = count($context['icons']); $i < $n; $i++)
1161
	{
1162
		$context['icons'][$i]['selected'] = $context['icon'] == $context['icons'][$i]['value'];
1163
		if ($context['icons'][$i]['selected'])
1164
			$context['icon_url'] = $context['icons'][$i]['url'];
1165
	}
1166
	if (empty($context['icon_url']))
1167
	{
1168
		$context['icon_url'] = $settings[file_exists($settings['theme_dir'] . '/images/post/' . $context['icon'] . '.png') ? 'images_url' : 'default_images_url'] . '/post/' . $context['icon'] . '.png';
1169
		array_unshift($context['icons'], array(
1170
			'value' => $context['icon'],
1171
			'name' => $txt['current_icon'],
1172
			'url' => $context['icon_url'],
1173
			'is_last' => empty($context['icons']),
1174
			'selected' => true,
1175
		));
1176
	}
1177
1178
	if (!empty($topic) && !empty($modSettings['topicSummaryPosts']))
1179
		getTopic();
1180
1181
	// If the user can post attachments prepare the warning labels.
1182
	if ($context['can_post_attachment'])
1183
	{
1184
		// 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.
1185
		$context['num_allowed_attachments'] = min(ini_get('max_file_uploads'), (empty($modSettings['attachmentNumPerPostLimit']) ? 50 : $modSettings['attachmentNumPerPostLimit'] - count($context['current_attachments'])));
1186
		$context['can_post_attachment_unapproved'] = allowedTo('post_attachment');
1187
		$context['attachment_restrictions'] = array();
1188
		$context['allowed_extensions'] = strtr(strtolower($modSettings['attachmentExtensions']), array(',' => ', '));
1189
		$attachmentRestrictionTypes = array('attachmentNumPerPostLimit', 'attachmentPostLimit', 'attachmentSizeLimit');
1190
		foreach ($attachmentRestrictionTypes as $type)
1191
			if (!empty($modSettings[$type]))
1192
			{
1193
				// Show the max number of attachments if not 0.
1194
				if ($type == 'attachmentNumPerPostLimit')
1195
					$context['attachment_restrictions'][] = sprintf($txt['attach_remaining'], $modSettings['attachmentNumPerPostLimit'] - $context['attachments']['quantity']);
1196
			}
1197
	}
1198
1199
	$context['back_to_topic'] = isset($_REQUEST['goback']) || (isset($_REQUEST['msg']) && !isset($_REQUEST['subject']));
1200
	$context['show_additional_options'] = !empty($_POST['additional_options']) || isset($_SESSION['temp_attachments']['post']) || isset($_GET['additionalOptions']);
1201
1202
	$context['is_new_topic'] = empty($topic);
1203
	$context['is_new_post'] = !isset($_REQUEST['msg']);
1204
	$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...
1205
1206
	// WYSIWYG only works if BBC is enabled
1207
	$modSettings['disable_wysiwyg'] = !empty($modSettings['disable_wysiwyg']) || empty($modSettings['enableBBC']);
1208
1209
	// Register this form in the session variables.
1210
	checkSubmitOnce('register');
1211
1212
	// Mentions
1213
	if (!empty($modSettings['enable_mentions']) && allowedTo('mention'))
1214
	{
1215
		loadJavaScriptFile('jquery.caret.min.js', array('defer' => true), 'smf_caret');
1216
		loadJavaScriptFile('jquery.atwho.min.js', array('defer' => true), 'smf_atwho');
1217
		loadJavaScriptFile('mentions.js', array('defer' => true, 'minimize' => true), 'smf_mentions');
1218
	}
1219
1220
	// quotedText.js
1221
	loadJavaScriptFile('quotedText.js', array('defer' => true, 'minimize' => true), 'smf_quotedText');
1222
1223
	addInlineJavaScript('
1224
	var current_attachments = [];');
1225
1226
	if (!empty($context['current_attachments']))
1227
	{
1228
		// Mock files to show already attached files.
1229
		foreach ($context['current_attachments'] as $key => $mock)
1230
			addInlineJavaScript('
1231
	current_attachments.push({
1232
		name: ' . JavaScriptEscape($mock['name']) . ',
1233
		size: ' . $mock['size'] . ',
1234
		attachID: ' . $mock['attachID'] . ',
1235
		approved: ' . $mock['approved'] . ',
1236
		type: ' . JavaScriptEscape(!empty($mock['mime_type']) ? $mock['mime_type'] : '') . ',
1237
		thumbID: ' . (!empty($mock['thumb']) ? $mock['thumb'] : 0) . '
1238
	});');
1239
	}
1240
1241
	// File Upload.
1242
	if ($context['can_post_attachment'])
1243
	{
1244
		$acceptedFiles = implode(',', array_map(function ($val) use ($smcFunc)
1245
		{
1246
			return '.' . $smcFunc['htmltrim']($val);
1247
		}, explode(',', $context['allowed_extensions'])));
1248
1249
		loadJavaScriptFile('dropzone.min.js', array('defer' => true), 'smf_dropzone');
1250
		loadJavaScriptFile('smf_fileUpload.js', array('defer' => true, 'minimize' => true), 'smf_fileUpload');
1251
		addInlineJavaScript('
1252
	$(function() {
1253
		smf_fileUpload({
1254
			dictDefaultMessage : ' . JavaScriptEscape($txt['attach_drop_zone']) . ',
1255
			dictFallbackMessage : ' . JavaScriptEscape($txt['attach_drop_zone_no']) . ',
1256
			dictCancelUpload : ' . JavaScriptEscape($txt['modify_cancel']) . ',
1257
			genericError: ' . JavaScriptEscape($txt['attach_php_error']) . ',
1258
			text_attachLeft: ' . JavaScriptEscape($txt['attachments_left']) . ',
1259
			text_deleteAttach: ' . JavaScriptEscape($txt['attached_file_delete']) . ',
1260
			text_attachDeleted: ' . JavaScriptEscape($txt['attached_file_deleted']) . ',
1261
			text_insertBBC: ' . JavaScriptEscape($txt['attached_insert_bbc']) . ',
1262
			text_attachUploaded: ' . JavaScriptEscape($txt['attached_file_uploaded']) . ',
1263
			text_attach_unlimited: ' . JavaScriptEscape($txt['attach_drop_unlimited']) . ',
1264
			text_totalMaxSize: ' . JavaScriptEscape($txt['attach_max_total_file_size_current']) . ',
1265
			text_max_size_progress: ' . JavaScriptEscape($txt['attach_max_size_progress']) . ',
1266
			dictMaxFilesExceeded: ' . JavaScriptEscape($txt['more_attachments_error']) . ',
1267
			dictInvalidFileType: ' . JavaScriptEscape(sprintf($txt['cant_upload_type'], $context['allowed_extensions'])) . ',
1268
			dictFileTooBig: ' . JavaScriptEscape(sprintf($txt['file_too_big'], comma_format($modSettings['attachmentSizeLimit'], 0))) . ',
1269
			acceptedFiles: ' . JavaScriptEscape($acceptedFiles) . ',
1270
			thumbnailWidth: ' . (!empty($modSettings['attachmentThumbWidth']) ? $modSettings['attachmentThumbWidth'] : 'null') . ',
1271
			thumbnailHeight: ' . (!empty($modSettings['attachmentThumbHeight']) ? $modSettings['attachmentThumbHeight'] : 'null') . ',
1272
			limitMultiFileUploadSize:' . round(max($modSettings['attachmentPostLimit'] - ($context['attachments']['total_size'] / 1024), 0)) * 1024 . ',
1273
			maxFileAmount: ' . (!empty($context['num_allowed_attachments']) ? $context['num_allowed_attachments'] : 'null') . ',
1274
			maxTotalSize: ' . (!empty($modSettings['attachmentPostLimit']) ? $modSettings['attachmentPostLimit'] : '0') . ',
1275
			maxFileSize: ' . (!empty($modSettings['attachmentSizeLimit']) ? $modSettings['attachmentSizeLimit'] : '0') . ',
1276
		});
1277
	});', true);
1278
	}
1279
1280
	// Knowing the current board ID might be handy.
1281
	addInlineJavaScript('
1282
	var current_board = ' . (empty($context['current_board']) ? 'null' : $context['current_board']) . ';', false);
1283
1284
	/* Now let's set up the fields for the posting form header...
1285
1286
		Each item in $context['posting_fields'] is an array similar to one of
1287
		the following:
1288
1289
		$context['posting_fields']['foo'] = array(
1290
			'label' => array(
1291
				'text' => $txt['foo'], // required
1292
				'class' => 'foo', // optional
1293
			),
1294
			'input' => array(
1295
				'type' => 'text', // required
1296
				'attributes' => array(
1297
					'name' => 'foo', // optional, defaults to posting field's key
1298
					'value' => $foo,
1299
					'size' => 80,
1300
				),
1301
			),
1302
		);
1303
1304
		$context['posting_fields']['bar'] = array(
1305
			'label' => array(
1306
				'text' => $txt['bar'], // required
1307
				'class' => 'bar', // optional
1308
			),
1309
			'input' => array(
1310
				'type' => 'select', // required
1311
				'attributes' => array(
1312
					'name' => 'bar', // optional, defaults to posting field's key
1313
				),
1314
				'options' => array(
1315
					'option_1' => array(
1316
						'label' => $txt['option_1'],
1317
						'value' => '1',
1318
						'selected' => true,
1319
					),
1320
					'option_2' => array(
1321
						'label' => $txt['option_2'],
1322
						'value' => '2',
1323
						'selected' => false,
1324
					),
1325
					'opt_group_1' => array(
1326
						'label' => $txt['opt_group_1'],
1327
						'options' => array(
1328
							'option_3' => array(
1329
								'label' => $txt['option_3'],
1330
								'value' => '3',
1331
								'selected' => false,
1332
							),
1333
							'option_4' => array(
1334
								'label' => $txt['option_4'],
1335
								'value' => '4',
1336
								'selected' => false,
1337
							),
1338
						),
1339
					),
1340
				),
1341
			),
1342
		);
1343
1344
		$context['posting_fields']['baz'] = array(
1345
			'label' => array(
1346
				'text' => $txt['baz'], // required
1347
				'class' => 'baz', // optional
1348
			),
1349
			'input' => array(
1350
				'type' => 'radio_select', // required
1351
				'attributes' => array(
1352
					'name' => 'baz', // optional, defaults to posting field's key
1353
				),
1354
				'options' => array(
1355
					'option_1' => array(
1356
						'label' => $txt['option_1'],
1357
						'value' => '1',
1358
						'selected' => true,
1359
					),
1360
					'option_2' => array(
1361
						'label' => $txt['option_2'],
1362
						'value' => '2',
1363
						'selected' => false,
1364
					),
1365
				),
1366
			),
1367
		);
1368
1369
		The label and input elements are required. The label text and input
1370
		type are also required. Other elements may be required or optional
1371
		depending on the situation.
1372
1373
		The input type can be one of the following:
1374
1375
		- text, password, color, date, datetime-local, email, month, number,
1376
		  range, tel, time, url, or week
1377
		- textarea
1378
		- checkbox
1379
		- select
1380
		- radio_select
1381
1382
		When the input type is text (etc.), textarea, or checkbox, the
1383
		'attributes' element is used to specify the initial value and any
1384
		other HTML attributes that might be necessary for the input field.
1385
1386
		When the input type is select or radio_select, the options element
1387
		is required in order to list the options that the user can select.
1388
		For the select type, these will be used to generate a typical select
1389
		menu. For the radio_select type, they will be used to make a div with
1390
		some radio buttons in it.
1391
1392
		Each option in the options array is itself an array of attributes. If
1393
		an option contains a sub-array of more options, then it will be
1394
		turned into an optgroup in the generated select menu. Note that the
1395
		radio_select type only supports simple options, not grouped ones.
1396
1397
		Both the label and the input can have a 'before' and/or 'after'
1398
		element. If used, these define literal HTML strings to be inserted
1399
		before or after the rest of the content of the label or input.
1400
1401
		Finally, it is possible to define an 'html' element for the label
1402
		and/or the input. If used, this will override the HTML that would
1403
		normally be generated in the template file using the other
1404
		information in the array. This should be avoided if at all possible.
1405
	*/
1406
	$context['posting_fields'] = array();
1407
1408
	// Guests must supply their name and email.
1409
	if (isset($context['name']) && isset($context['email']))
1410
	{
1411
		$context['posting_fields']['guestname'] = array(
1412
			'label' => array(
1413
				'text' => $txt['name'],
1414
				'class' => isset($context['post_error']['long_name']) || isset($context['post_error']['no_name']) || isset($context['post_error']['bad_name']) ? 'error' : '',
1415
			),
1416
			'input' => array(
1417
				'type' => 'text',
1418
				'attributes' => array(
1419
					'size' => 25,
1420
					'value' => $context['name'],
1421
					'required' => true,
1422
				),
1423
			),
1424
		);
1425
1426
		if (empty($modSettings['guest_post_no_email']))
1427
		{
1428
			$context['posting_fields']['email'] = array(
1429
				'label' => array(
1430
					'text' => $txt['email'],
1431
					'class' => isset($context['post_error']['no_email']) || isset($context['post_error']['bad_email']) ? 'error' : '',
1432
				),
1433
				'input' => array(
1434
					'type' => 'email',
1435
					'attributes' => array(
1436
						'size' => 25,
1437
						'value' => $context['email'],
1438
						'required' => true,
1439
					),
1440
				),
1441
			);
1442
		}
1443
	}
1444
1445
	// Gotta post it somewhere.
1446
	if (empty($board) && !$context['make_event'])
1447
	{
1448
		$context['posting_fields']['board'] = array(
1449
			'label' => array(
1450
				'text' => $txt['calendar_post_in'],
1451
			),
1452
			'input' => array(
1453
				'type' => 'select',
1454
				'options' => array(),
1455
			),
1456
		);
1457
		foreach ($board_list as $category)
1458
		{
1459
			$context['posting_fields']['board']['input']['options'][$category['name']] = array('options' => array());
1460
1461
			foreach ($category['boards'] as $brd)
1462
				$context['posting_fields']['board']['input']['options'][$category['name']]['options'][$brd['name']] = array(
1463
					'value' => $brd['id'],
1464
					'selected' => (bool) $brd['selected'],
1465
					'label' => ($brd['child_level'] > 0 ? str_repeat('==', $brd['child_level'] - 1) . '=&gt;' : '') . ' ' . $brd['name'],
1466
				);
1467
		}
1468
	}
1469
1470
	// Gotta have a subject.
1471
	$context['posting_fields']['subject'] = array(
1472
		'label' => array(
1473
			'text' => $txt['subject'],
1474
			'class' => isset($context['post_error']['no_subject']) ? 'error' : '',
1475
		),
1476
		'input' => array(
1477
			'type' => 'text',
1478
			'attributes' => array(
1479
				'size' => 80,
1480
				'maxlength' => !empty($topic) ? 84 : 80,
1481
				'value' => $context['subject'],
1482
				'required' => true,
1483
			),
1484
		),
1485
	);
1486
1487
	// Icons are fun.
1488
	$context['posting_fields']['icon'] = array(
1489
		'label' => array(
1490
			'text' => $txt['message_icon'],
1491
		),
1492
		'input' => array(
1493
			'type' => 'select',
1494
			'attributes' => array(
1495
				'id' => 'icon',
1496
				'onchange' => 'showimage();',
1497
			),
1498
			'options' => array(),
1499
			'after' => ' <img id="icons" src="' . $context['icon_url'] . '">',
1500
		),
1501
	);
1502
	foreach ($context['icons'] as $icon)
1503
	{
1504
		$context['posting_fields']['icon']['input']['options'][$icon['name']] = array(
1505
			'value' => $icon['value'],
1506
			'selected' => $icon['value'] == $context['icon'],
1507
		);
1508
	}
1509
1510
	// Finally, load the template.
1511
	if (!isset($_REQUEST['xml']))
1512
		loadTemplate('Post');
1513
1514
	call_integration_hook('integrate_post_end');
1515
}
1516
1517
/**
1518
 * Posts or saves the message composed with Post().
1519
 *
1520
 * requires various permissions depending on the action.
1521
 * handles attachment, post, and calendar saving.
1522
 * sends off notifications, and allows for announcements and moderation.
1523
 * accessed from ?action=post2.
1524
 */
1525
function Post2()
1526
{
1527
	global $board, $topic, $txt, $modSettings, $sourcedir, $context;
1528
	global $user_info, $board_info, $smcFunc, $settings;
1529
1530
	// Sneaking off, are we?
1531
	if (empty($_POST) && empty($topic))
1532
	{
1533
		if (empty($_SERVER['CONTENT_LENGTH']))
1534
			redirectexit('action=post;board=' . $board . '.0');
1535
		else
1536
			fatal_lang_error('post_upload_error', false);
1537
	}
1538
	elseif (empty($_POST) && !empty($topic))
1539
		redirectexit('action=post;topic=' . $topic . '.0');
1540
1541
	// No need!
1542
	$context['robot_no_index'] = true;
1543
1544
	// Prevent double submission of this form.
1545
	checkSubmitOnce('check');
1546
1547
	// No errors as yet.
1548
	$post_errors = array();
1549
1550
	// If the session has timed out, let the user re-submit their form.
1551
	if (checkSession('post', '', false) != '')
1552
		$post_errors[] = 'session_timeout';
1553
1554
	// Wrong verification code?
1555
	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)))
1556
	{
1557
		require_once($sourcedir . '/Subs-Editor.php');
1558
		$verificationOptions = array(
1559
			'id' => 'post',
1560
		);
1561
		$context['require_verification'] = create_control_verification($verificationOptions, true);
1562
		if (is_array($context['require_verification']))
1563
			$post_errors = array_merge($post_errors, $context['require_verification']);
1564
	}
1565
1566
	require_once($sourcedir . '/Subs-Post.php');
1567
	loadLanguage('Post');
1568
1569
	call_integration_hook('integrate_post2_start', array(&$post_errors));
1570
1571
	// Drafts enabled and needed?
1572
	if (!empty($modSettings['drafts_post_enabled']) && (isset($_POST['save_draft']) || isset($_POST['id_draft'])))
1573
		require_once($sourcedir . '/Drafts.php');
1574
1575
	// First check to see if they are trying to delete any current attachments.
1576
	if (isset($_POST['attach_del']))
1577
	{
1578
		$keep_temp = array();
1579
		$keep_ids = array();
1580
		foreach ($_POST['attach_del'] as $dummy)
1581
			if (strpos($dummy, 'post_tmp_' . $user_info['id']) !== false)
1582
				$keep_temp[] = $dummy;
1583
			else
1584
				$keep_ids[] = (int) $dummy;
1585
1586
		if (isset($_SESSION['temp_attachments']))
1587
			foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
1588
			{
1589
				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)
1590
					continue;
1591
1592
				unset($_SESSION['temp_attachments'][$attachID]);
1593
				unlink($attachment['tmp_name']);
1594
			}
1595
1596
		if (!empty($_REQUEST['msg']))
1597
		{
1598
			require_once($sourcedir . '/ManageAttachments.php');
1599
			$attachmentQuery = array(
1600
				'attachment_type' => 0,
1601
				'id_msg' => (int) $_REQUEST['msg'],
1602
				'not_id_attach' => $keep_ids,
1603
			);
1604
			removeAttachments($attachmentQuery);
1605
		}
1606
	}
1607
1608
	// Then try to upload any attachments.
1609
	$context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments')));
1610
	if ($context['can_post_attachment'] && empty($_POST['from_qr']))
1611
	{
1612
		require_once($sourcedir . '/Subs-Attachments.php');
1613
		processAttachments();
1614
	}
1615
1616
	// They've already uploaded some attachments, but they don't have permission to post them
1617
	// This can sometimes happen when they came from ?action=calendar;sa=post
1618
	if (!$context['can_post_attachment'] && !empty($_SESSION['already_attached']))
1619
	{
1620
		require_once($sourcedir . '/ManageAttachments.php');
1621
1622
		foreach ($_SESSION['already_attached'] as $attachID => $attachment)
1623
			removeAttachments(array('id_attach' => $attachID));
1624
1625
		unset($_SESSION['already_attached']);
1626
1627
		$post_errors[] = array('cannot_post_attachment', array($board_info['name']));
1628
	}
1629
1630
	$can_approve = allowedTo('approve_posts');
1631
1632
	// If this isn't a new topic load the topic info that we need.
1633
	if (!empty($topic))
1634
	{
1635
		$request = $smcFunc['db_query']('', '
1636
			SELECT locked, is_sticky, id_poll, approved, id_first_msg, id_last_msg, id_member_started, id_board
1637
			FROM {db_prefix}topics
1638
			WHERE id_topic = {int:current_topic}
1639
			LIMIT 1',
1640
			array(
1641
				'current_topic' => $topic,
1642
			)
1643
		);
1644
		$topic_info = $smcFunc['db_fetch_assoc']($request);
1645
		$smcFunc['db_free_result']($request);
1646
1647
		// Though the topic should be there, it might have vanished.
1648
		if (!is_array($topic_info))
1649
			fatal_lang_error('topic_doesnt_exist', 404);
1650
1651
		// Did this topic suddenly move? Just checking...
1652
		if ($topic_info['id_board'] != $board)
1653
			fatal_lang_error('not_a_topic');
1654
1655
		// Do the permissions and approval stuff...
1656
		$becomesApproved = true;
1657
1658
		// Replies to unapproved topics are unapproved by default (but not for moderators)
1659
		if (empty($topic_info['approved']) && !$can_approve)
1660
		{
1661
			$becomesApproved = false;
1662
1663
			// Set a nice session var...
1664
			$_SESSION['becomesUnapproved'] = true;
1665
		}
1666
	}
1667
1668
	// Replying to a topic?
1669
	if (!empty($topic) && !isset($_REQUEST['msg']))
1670
	{
1671
		// Don't allow a post if it's locked.
1672
		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...
1673
			fatal_lang_error('topic_locked', false);
1674
1675
		// Sorry, multiple polls aren't allowed... yet.  You should stop giving me ideas :P.
1676
		if (isset($_REQUEST['poll']) && $topic_info['id_poll'] > 0)
1677
			unset($_REQUEST['poll']);
1678
1679
		elseif ($topic_info['id_member_started'] != $user_info['id'])
1680
		{
1681
			if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any'))
1682
				$becomesApproved = false;
1683
1684
			else
1685
				isAllowedTo('post_reply_any');
1686
		}
1687
		elseif (!allowedTo('post_reply_any'))
1688
		{
1689
			if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own'))
1690
				$becomesApproved = false;
1691
1692
			else
1693
				isAllowedTo('post_reply_own');
1694
		}
1695
1696
		if (isset($_POST['lock']))
1697
		{
1698
			// Nothing is changed to the lock.
1699
			if (empty($topic_info['locked']) == empty($_POST['lock']))
1700
				unset($_POST['lock']);
1701
1702
			// You're have no permission to lock this topic.
1703
			elseif (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']))
1704
				unset($_POST['lock']);
1705
1706
			// You are allowed to (un)lock your own topic only.
1707
			elseif (!allowedTo('lock_any'))
1708
			{
1709
				// You cannot override a moderator lock.
1710
				if ($topic_info['locked'] == 1)
1711
					unset($_POST['lock']);
1712
1713
				else
1714
					$_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
1715
			}
1716
			// Hail mighty moderator, (un)lock this topic immediately.
1717
			else
1718
			{
1719
				$_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
1720
1721
				// Did someone (un)lock this while you were posting?
1722
				if (isset($_POST['already_locked']) && $_POST['already_locked'] != $topic_info['locked'])
1723
					$post_errors[] = 'topic_' . (empty($topic_info['locked']) ? 'un' : '') . 'locked';
1724
			}
1725
		}
1726
1727
		// So you wanna (un)sticky this...let's see.
1728
		if (isset($_POST['sticky']) && ($_POST['sticky'] == $topic_info['is_sticky'] || !allowedTo('make_sticky')))
1729
			unset($_POST['sticky']);
1730
		elseif (isset($_POST['sticky']))
1731
		{
1732
			// Did someone (un)sticky this while you were posting?
1733
			if (isset($_POST['already_sticky']) && $_POST['already_sticky'] != $topic_info['is_sticky'])
1734
				$post_errors[] = 'topic_' . (empty($topic_info['is_sticky']) ? 'un' : '') . 'sticky';
1735
		}
1736
1737
		// If drafts are enabled, then pass this off
1738
		if (!empty($modSettings['drafts_post_enabled']) && isset($_POST['save_draft']))
1739
		{
1740
			SaveDraft($post_errors);
1741
			return Post();
1742
		}
1743
1744
		// If the number of replies has changed, if the setting is enabled, go back to Post() - which handles the error.
1745
		if (isset($_POST['last_msg']) && $topic_info['id_last_msg'] > $_POST['last_msg'])
1746
		{
1747
			$_REQUEST['preview'] = true;
1748
			return Post();
1749
		}
1750
1751
		$posterIsGuest = $user_info['is_guest'];
1752
	}
1753
	// Posting a new topic.
1754
	elseif (empty($topic))
1755
	{
1756
		// Now don't be silly, new topics will get their own id_msg soon enough.
1757
		unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
1758
1759
		// Do like, the permissions, for safety and stuff...
1760
		$becomesApproved = true;
1761
		if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics'))
1762
			$becomesApproved = false;
1763
		else
1764
			isAllowedTo('post_new');
1765
1766
		if (isset($_POST['lock']))
1767
		{
1768
			// New topics are by default not locked.
1769
			if (empty($_POST['lock']))
1770
				unset($_POST['lock']);
1771
			// Besides, you need permission.
1772
			elseif (!allowedTo(array('lock_any', 'lock_own')))
1773
				unset($_POST['lock']);
1774
			// A moderator-lock (1) can override a user-lock (2).
1775
			else
1776
				$_POST['lock'] = allowedTo('lock_any') ? 1 : 2;
1777
		}
1778
1779
		if (isset($_POST['sticky']) && (empty($_POST['sticky']) || !allowedTo('make_sticky')))
1780
			unset($_POST['sticky']);
1781
1782
		// Saving your new topic as a draft first?
1783
		if (!empty($modSettings['drafts_post_enabled']) && isset($_POST['save_draft']))
1784
		{
1785
			SaveDraft($post_errors);
1786
			return Post();
1787
		}
1788
1789
		$posterIsGuest = $user_info['is_guest'];
1790
	}
1791
	// Modifying an existing message?
1792
	elseif (isset($_REQUEST['msg']) && !empty($topic))
1793
	{
1794
		$_REQUEST['msg'] = (int) $_REQUEST['msg'];
1795
1796
		$request = $smcFunc['db_query']('', '
1797
			SELECT id_member, poster_name, poster_email, poster_time, approved
1798
			FROM {db_prefix}messages
1799
			WHERE id_msg = {int:id_msg}
1800
			LIMIT 1',
1801
			array(
1802
				'id_msg' => $_REQUEST['msg'],
1803
			)
1804
		);
1805
		if ($smcFunc['db_num_rows']($request) == 0)
1806
			fatal_lang_error('cant_find_messages', false);
1807
		$row = $smcFunc['db_fetch_assoc']($request);
1808
		$smcFunc['db_free_result']($request);
1809
1810
		if (!empty($topic_info['locked']) && !allowedTo('moderate_board'))
1811
			fatal_lang_error('topic_locked', false);
1812
1813
		if (isset($_POST['lock']))
1814
		{
1815
			// Nothing changes to the lock status.
1816
			if ((empty($_POST['lock']) && empty($topic_info['locked'])) || (!empty($_POST['lock']) && !empty($topic_info['locked'])))
1817
				unset($_POST['lock']);
1818
			// You're simply not allowed to (un)lock this.
1819
			elseif (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']))
1820
				unset($_POST['lock']);
1821
			// You're only allowed to lock your own topics.
1822
			elseif (!allowedTo('lock_any'))
1823
			{
1824
				// You're not allowed to break a moderator's lock.
1825
				if ($topic_info['locked'] == 1)
1826
					unset($_POST['lock']);
1827
				// Lock it with a soft lock or unlock it.
1828
				else
1829
					$_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
1830
			}
1831
			// You must be the moderator.
1832
			else
1833
			{
1834
				$_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
1835
1836
				// Did someone (un)lock this while you were posting?
1837
				if (isset($_POST['already_locked']) && $_POST['already_locked'] != $topic_info['locked'])
1838
					$post_errors[] = 'topic_' . (empty($topic_info['locked']) ? 'un' : '') . 'locked';
1839
			}
1840
		}
1841
1842
		// Change the sticky status of this topic?
1843
		if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $topic_info['is_sticky']))
1844
			unset($_POST['sticky']);
1845
		elseif (isset($_POST['sticky']))
1846
		{
1847
			// Did someone (un)sticky this while you were posting?
1848
			if (isset($_POST['already_sticky']) && $_POST['already_sticky'] != $topic_info['is_sticky'])
1849
				$post_errors[] = 'topic_' . (empty($topic_info['locked']) ? 'un' : '') . 'stickied';
1850
		}
1851
1852
		if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
1853
		{
1854
			if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
1855
				fatal_lang_error('modify_post_time_passed', false);
1856
			elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_own'))
1857
				isAllowedTo('modify_replies');
1858
			else
1859
				isAllowedTo('modify_own');
1860
		}
1861
		elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_any'))
1862
		{
1863
			isAllowedTo('modify_replies');
1864
1865
			// If you're modifying a reply, I say it better be logged...
1866
			$moderationAction = true;
1867
		}
1868
		else
1869
		{
1870
			isAllowedTo('modify_any');
1871
1872
			// Log it, assuming you're not modifying your own post.
1873
			if ($row['id_member'] != $user_info['id'])
1874
				$moderationAction = true;
1875
		}
1876
1877
		// If drafts are enabled, then lets send this off to save
1878
		if (!empty($modSettings['drafts_post_enabled']) && isset($_POST['save_draft']))
1879
		{
1880
			SaveDraft($post_errors);
1881
			return Post();
1882
		}
1883
1884
		$posterIsGuest = empty($row['id_member']);
1885
1886
		// Can they approve it?
1887
		$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...
1888
		$becomesApproved = $modSettings['postmod_active'] ? ($can_approve && !$row['approved'] ? $approve_checked : $row['approved']) : 1;
1889
		$approve_has_changed = $row['approved'] != $becomesApproved;
1890
1891
		if (!allowedTo('moderate_forum') || !$posterIsGuest)
1892
		{
1893
			$_POST['guestname'] = $row['poster_name'];
1894
			$_POST['email'] = $row['poster_email'];
1895
		}
1896
1897
		// Update search api
1898
		require_once($sourcedir . '/Search.php');
1899
		$searchAPI = findSearchAPI();
1900
		if ($searchAPI->supportsMethod('postRemoved'))
1901
			$searchAPI->postRemoved($_REQUEST['msg']);
1902
1903
	}
1904
1905
	// In case we have approval permissions and want to override.
1906
	if ($can_approve && $modSettings['postmod_active'])
1907
	{
1908
		$becomesApproved = isset($_POST['quickReply']) || !empty($_REQUEST['approve']) ? 1 : 0;
1909
		$approve_has_changed = isset($row['approved']) ? $row['approved'] != $becomesApproved : false;
1910
	}
1911
1912
	// If the poster is a guest evaluate the legality of name and email.
1913
	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...
1914
	{
1915
		$_POST['guestname'] = !isset($_POST['guestname']) ? '' : trim($_POST['guestname']);
1916
		$_POST['email'] = !isset($_POST['email']) ? '' : trim($_POST['email']);
1917
1918
		if ($_POST['guestname'] == '' || $_POST['guestname'] == '_')
1919
			$post_errors[] = 'no_name';
1920
		if ($smcFunc['strlen']($_POST['guestname']) > 25)
1921
			$post_errors[] = 'long_name';
1922
1923
		if (empty($modSettings['guest_post_no_email']))
1924
		{
1925
			// Only check if they changed it!
1926
			if (!isset($row) || $row['poster_email'] != $_POST['email'])
1927
			{
1928
				if (!allowedTo('moderate_forum') && (!isset($_POST['email']) || $_POST['email'] == ''))
1929
					$post_errors[] = 'no_email';
1930
				if (!allowedTo('moderate_forum') && !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL))
1931
					$post_errors[] = 'bad_email';
1932
			}
1933
1934
			// Now make sure this email address is not banned from posting.
1935
			isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
1936
		}
1937
1938
		// In case they are making multiple posts this visit, help them along by storing their name.
1939
		if (empty($post_errors))
1940
		{
1941
			$_SESSION['guest_name'] = $_POST['guestname'];
1942
			$_SESSION['guest_email'] = $_POST['email'];
1943
		}
1944
	}
1945
1946
	// Coming from the quickReply?
1947
	if (isset($_POST['quickReply']))
1948
		$_POST['message'] = $_POST['quickReply'];
1949
1950
	// Check the subject and message.
1951
	if (!isset($_POST['subject']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['subject'])) === '')
1952
		$post_errors[] = 'no_subject';
1953
	if (!isset($_POST['message']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['message']), ENT_QUOTES) === '')
1954
		$post_errors[] = 'no_message';
1955
	elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_POST['message']) > $modSettings['max_messageLength'])
1956
		$post_errors[] = array('long_message', array($modSettings['max_messageLength']));
1957
	else
1958
	{
1959
		// Prepare the message a bit for some additional testing.
1960
		$_POST['message'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
1961
1962
		// Preparse code. (Zef)
1963
		if ($user_info['is_guest'])
1964
			$user_info['name'] = $_POST['guestname'];
1965
		preparsecode($_POST['message']);
1966
1967
		// Let's see if there's still some content left without the tags.
1968
		if ($smcFunc['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), implode('', $context['allowed_html_tags']))) === '' && (!allowedTo('bbc_html') || strpos($_POST['message'], '[html]') === false))
1969
			$post_errors[] = 'no_message';
1970
1971
	}
1972
	if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && $smcFunc['htmltrim']($_POST['evtitle']) === '')
1973
		$post_errors[] = 'no_event';
1974
	// You are not!
1975
	if (isset($_POST['message']) && strtolower($_POST['message']) == 'i am the administrator.' && !$user_info['is_admin'])
1976
		fatal_error('Knave! Masquerader! Charlatan!', false);
1977
1978
	// Validate the poll...
1979
	if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1')
1980
	{
1981
		if (!empty($topic) && !isset($_REQUEST['msg']))
1982
			fatal_lang_error('no_access', false);
1983
1984
		// This is a new topic... so it's a new poll.
1985
		if (empty($topic))
1986
			isAllowedTo('poll_post');
1987
		// Can you add to your own topics?
1988
		elseif ($user_info['id'] == $topic_info['id_member_started'] && !allowedTo('poll_add_any'))
1989
			isAllowedTo('poll_add_own');
1990
		// Can you add polls to any topic, then?
1991
		else
1992
			isAllowedTo('poll_add_any');
1993
1994
		if (!isset($_POST['question']) || trim($_POST['question']) == '')
1995
			$post_errors[] = 'no_question';
1996
1997
		$_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']);
1998
1999
		// Get rid of empty ones.
2000
		foreach ($_POST['options'] as $k => $option)
2001
			if ($option == '')
2002
				unset($_POST['options'][$k], $_POST['options'][$k]);
2003
2004
		// What are you going to vote between with one choice?!?
2005
		if (count($_POST['options']) < 2)
2006
			$post_errors[] = 'poll_few';
2007
		elseif (count($_POST['options']) > 256)
2008
			$post_errors[] = 'poll_many';
2009
	}
2010
2011
	if ($posterIsGuest)
2012
	{
2013
		// If user is a guest, make sure the chosen name isn't taken.
2014
		require_once($sourcedir . '/Subs-Members.php');
2015
		if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($row['poster_name']) || $_POST['guestname'] != $row['poster_name']))
2016
			$post_errors[] = 'bad_name';
2017
	}
2018
	// If the user isn't a guest, get his or her name and email.
2019
	elseif (!isset($_REQUEST['msg']))
2020
	{
2021
		$_POST['guestname'] = $user_info['username'];
2022
		$_POST['email'] = $user_info['email'];
2023
	}
2024
2025
	// Any mistakes?
2026
	if (!empty($post_errors))
2027
	{
2028
		// Previewing.
2029
		$_REQUEST['preview'] = true;
2030
2031
		return Post($post_errors);
2032
	}
2033
2034
	// Previewing? Go back to start.
2035
	if (isset($_REQUEST['preview']))
2036
	{
2037
		if (checkSession('post', '', false) != '')
2038
		{
2039
			loadLanguage('Errors');
2040
			$post_errors[] = 'session_timeout';
2041
			unset ($_POST['preview'], $_REQUEST['xml']); // just in case
2042
		}
2043
		return Post($post_errors);
2044
	}
2045
2046
	// Make sure the user isn't spamming the board.
2047
	if (!isset($_REQUEST['msg']))
2048
		spamProtection('post');
2049
2050
	// At about this point, we're posting and that's that.
2051
	ignore_user_abort(true);
2052
	@set_time_limit(300);
2053
2054
	// Add special html entities to the subject, name, and email.
2055
	$_POST['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
2056
	$_POST['guestname'] = $smcFunc['htmlspecialchars']($_POST['guestname']);
2057
	$_POST['email'] = $smcFunc['htmlspecialchars']($_POST['email']);
2058
	$_POST['modify_reason'] = empty($_POST['modify_reason']) ? '' : strtr($smcFunc['htmlspecialchars']($_POST['modify_reason']), array("\r" => '', "\n" => '', "\t" => ''));
2059
2060
	// At this point, we want to make sure the subject isn't too long.
2061
	if ($smcFunc['strlen']($_POST['subject']) > 100)
2062
		$_POST['subject'] = $smcFunc['substr']($_POST['subject'], 0, 100);
2063
2064
	// Same with the "why did you edit this" text.
2065
	if ($smcFunc['strlen']($_POST['modify_reason']) > 100)
2066
		$_POST['modify_reason'] = $smcFunc['substr']($_POST['modify_reason'], 0, 100);
2067
2068
	// Make the poll...
2069
	if (isset($_REQUEST['poll']))
2070
	{
2071
		// Make sure that the user has not entered a ridiculous number of options..
2072
		if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0)
2073
			$_POST['poll_max_votes'] = 1;
2074
		elseif ($_POST['poll_max_votes'] > count($_POST['options']))
2075
			$_POST['poll_max_votes'] = count($_POST['options']);
2076
		else
2077
			$_POST['poll_max_votes'] = (int) $_POST['poll_max_votes'];
2078
2079
		$_POST['poll_expire'] = (int) $_POST['poll_expire'];
2080
		$_POST['poll_expire'] = $_POST['poll_expire'] > 9999 ? 9999 : ($_POST['poll_expire'] < 0 ? 0 : $_POST['poll_expire']);
2081
2082
		// Just set it to zero if it's not there..
2083
		if (!isset($_POST['poll_hide']))
2084
			$_POST['poll_hide'] = 0;
2085
		else
2086
			$_POST['poll_hide'] = (int) $_POST['poll_hide'];
2087
		$_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0;
2088
2089
		$_POST['poll_guest_vote'] = isset($_POST['poll_guest_vote']) ? 1 : 0;
2090
		// Make sure guests are actually allowed to vote generally.
2091
		if ($_POST['poll_guest_vote'])
2092
		{
2093
			require_once($sourcedir . '/Subs-Members.php');
2094
			$allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
2095
			if (!in_array(-1, $allowedVoteGroups['allowed']))
2096
				$_POST['poll_guest_vote'] = 0;
2097
		}
2098
2099
		// If the user tries to set the poll too far in advance, don't let them.
2100
		if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1)
2101
			fatal_lang_error('poll_range_error', false);
2102
		// Don't allow them to select option 2 for hidden results if it's not time limited.
2103
		elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2)
2104
			$_POST['poll_hide'] = 1;
2105
2106
		// Clean up the question and answers.
2107
		$_POST['question'] = $smcFunc['htmlspecialchars']($_POST['question']);
2108
		$_POST['question'] = $smcFunc['truncate']($_POST['question'], 255);
2109
		$_POST['question'] = preg_replace('~&amp;#(\d{4,5}|[2-9]\d{2,4}|1[2-9]\d);~', '&#$1;', $_POST['question']);
2110
		$_POST['options'] = htmlspecialchars__recursive($_POST['options']);
2111
	}
2112
2113
	// ...or attach a new file...
2114
	if ($context['can_post_attachment'] && !empty($_SESSION['temp_attachments']) && empty($_POST['from_qr']))
2115
	{
2116
		$attachIDs = array();
2117
		$attach_errors = array();
2118
		if (!empty($context['we_are_history']))
2119
			$attach_errors[] = '<dd>' . $txt['error_temp_attachments_flushed'] . '<br><br></dd>';
2120
2121
		foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
2122
		{
2123
			if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
2124
				continue;
2125
2126
			// If there was an initial error just show that message.
2127
			if ($attachID == 'initial_error')
2128
			{
2129
				$attach_errors[] = '<dt>' . $txt['attach_no_upload'] . '</dt>';
2130
				$attach_errors[] = '<dd>' . (is_array($attachment) ? vsprintf($txt[$attachment[0]], $attachment[1]) : $txt[$attachment]) . '</dd>';
2131
2132
				unset($_SESSION['temp_attachments']);
2133
				break;
2134
			}
2135
2136
			$attachmentOptions = array(
2137
				'post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0,
2138
				'poster' => $user_info['id'],
2139
				'name' => $attachment['name'],
2140
				'tmp_name' => $attachment['tmp_name'],
2141
				'size' => isset($attachment['size']) ? $attachment['size'] : 0,
2142
				'mime_type' => isset($attachment['type']) ? $attachment['type'] : '',
2143
				'id_folder' => isset($attachment['id_folder']) ? $attachment['id_folder'] : $modSettings['currentAttachmentUploadDir'],
2144
				'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment'),
2145
				'errors' => $attachment['errors'],
2146
			);
2147
2148
			if (empty($attachment['errors']))
2149
			{
2150
				if (createAttachment($attachmentOptions))
2151
				{
2152
					$attachIDs[] = $attachmentOptions['id'];
2153
					if (!empty($attachmentOptions['thumb']))
2154
						$attachIDs[] = $attachmentOptions['thumb'];
2155
				}
2156
			}
2157
			else
2158
				$attach_errors[] = '<dt>&nbsp;</dt>';
2159
2160
			if (!empty($attachmentOptions['errors']))
2161
			{
2162
				// Sort out the errors for display and delete any associated files.
2163
				$attach_errors[] = '<dt>' . vsprintf($txt['attach_warning'], $attachment['name']) . '</dt>';
2164
				$log_these = array('attachments_no_create', 'attachments_no_write', 'attach_timeout', 'ran_out_of_space', 'cant_access_upload_path', 'attach_0_byte_file');
2165
				foreach ($attachmentOptions['errors'] as $error)
2166
				{
2167
					if (!is_array($error))
2168
					{
2169
						$attach_errors[] = '<dd>' . $txt[$error] . '</dd>';
2170
						if (in_array($error, $log_these))
2171
							log_error($attachment['name'] . ': ' . $txt[$error], 'critical');
2172
					}
2173
					else
2174
						$attach_errors[] = '<dd>' . vsprintf($txt[$error[0]], $error[1]) . '</dd>';
2175
				}
2176
				if (file_exists($attachment['tmp_name']))
2177
					unlink($attachment['tmp_name']);
2178
			}
2179
		}
2180
		unset($_SESSION['temp_attachments']);
2181
	}
2182
2183
	// Make the poll...
2184
	if (isset($_REQUEST['poll']))
2185
	{
2186
		// Create the poll.
2187
		$id_poll = $smcFunc['db_insert']('',
2188
			'{db_prefix}polls',
2189
			array(
2190
				'question' => 'string-255', 'hide_results' => 'int', 'max_votes' => 'int', 'expire_time' => 'int', 'id_member' => 'int',
2191
				'poster_name' => 'string-255', 'change_vote' => 'int', 'guest_vote' => 'int'
2192
			),
2193
			array(
2194
				$_POST['question'], $_POST['poll_hide'], $_POST['poll_max_votes'], (empty($_POST['poll_expire']) ? 0 : time() + $_POST['poll_expire'] * 3600 * 24), $user_info['id'],
2195
				$_POST['guestname'], $_POST['poll_change_vote'], $_POST['poll_guest_vote'],
2196
			),
2197
			array('id_poll'),
2198
			1
2199
		);
2200
2201
		// Create each answer choice.
2202
		$i = 0;
2203
		$pollOptions = array();
2204
		foreach ($_POST['options'] as $option)
2205
		{
2206
			$pollOptions[] = array($id_poll, $i, $option);
2207
			$i++;
2208
		}
2209
2210
		$smcFunc['db_insert']('insert',
2211
			'{db_prefix}poll_choices',
2212
			array('id_poll' => 'int', 'id_choice' => 'int', 'label' => 'string-255'),
2213
			$pollOptions,
2214
			array('id_poll', 'id_choice')
2215
		);
2216
2217
		call_integration_hook('integrate_poll_add_edit', array($id_poll, false));
2218
	}
2219
	else
2220
		$id_poll = 0;
2221
2222
	// Creating a new topic?
2223
	$newTopic = empty($_REQUEST['msg']) && empty($topic);
2224
2225
	// Check the icon.
2226
	if (!isset($_POST['icon']))
2227
		$_POST['icon'] = 'xx';
2228
2229
	else
2230
	{
2231
		$_POST['icon'] = $smcFunc['htmlspecialchars']($_POST['icon']);
2232
2233
		// Need to figure it out if this is a valid icon name.
2234
		if ((!file_exists($settings['theme_dir'] . '/images/post/' . $_POST['icon'] . '.png')) && (!file_exists($settings['default_theme_dir'] . '/images/post/' . $_POST['icon'] . '.png')))
2235
			$_POST['icon'] = 'xx';
2236
	}
2237
2238
	// Collect all parameters for the creation or modification of a post.
2239
	$msgOptions = array(
2240
		'id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'],
2241
		'subject' => $_POST['subject'],
2242
		'body' => $_POST['message'],
2243
		'icon' => preg_replace('~[\./\\\\*:"\'<>]~', '', $_POST['icon']),
2244
		'smileys_enabled' => !isset($_POST['ns']),
2245
		'attachments' => empty($attachIDs) ? array() : $attachIDs,
2246
		'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...
2247
	);
2248
	$topicOptions = array(
2249
		'id' => empty($topic) ? 0 : $topic,
2250
		'board' => $board,
2251
		'poll' => isset($_REQUEST['poll']) ? $id_poll : null,
2252
		'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null,
2253
		'sticky_mode' => isset($_POST['sticky']) ? (int) $_POST['sticky'] : null,
2254
		'mark_as_read' => true,
2255
		'is_approved' => !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']),
2256
	);
2257
	$posterOptions = array(
2258
		'id' => $user_info['id'],
2259
		'name' => $_POST['guestname'],
2260
		'email' => $_POST['email'],
2261
		'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count'],
2262
	);
2263
2264
	// This is an already existing message. Edit it.
2265
	if (!empty($_REQUEST['msg']))
2266
	{
2267
		// Have admins allowed people to hide their screwups?
2268
		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...
2269
		{
2270
			$msgOptions['modify_time'] = time();
2271
			$msgOptions['modify_name'] = $user_info['name'];
2272
			$msgOptions['modify_reason'] = $_POST['modify_reason'];
2273
		}
2274
2275
		// This will save some time...
2276
		if (empty($approve_has_changed))
2277
			unset($msgOptions['approved']);
2278
2279
		modifyPost($msgOptions, $topicOptions, $posterOptions);
2280
	}
2281
	// This is a new topic or an already existing one. Save it.
2282
	else
2283
	{
2284
		createPost($msgOptions, $topicOptions, $posterOptions);
2285
2286
		if (isset($topicOptions['id']))
2287
			$topic = $topicOptions['id'];
2288
	}
2289
2290
	// Are there attachments already uploaded and waiting to be assigned?
2291
	if (!empty($msgOptions['id']) && !empty($_SESSION['already_attached']))
2292
	{
2293
		require_once($sourcedir . '/Subs-Attachments.php');
2294
		assignAttachments($_SESSION['already_attached'], $msgOptions['id']);
2295
		unset($_SESSION['already_attached']);
2296
	}
2297
2298
	// If we had a draft for this, its time to remove it since it was just posted
2299
	if (!empty($modSettings['drafts_post_enabled']) && !empty($_POST['id_draft']))
2300
		DeleteDraft($_POST['id_draft']);
2301
2302
	// Editing or posting an event?
2303
	if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1))
2304
	{
2305
		require_once($sourcedir . '/Subs-Calendar.php');
2306
2307
		// Make sure they can link an event to this post.
2308
		canLinkEvent();
2309
2310
		// Insert the event.
2311
		$eventOptions = array(
2312
			'board' => $board,
2313
			'topic' => $topic,
2314
			'title' => $_POST['evtitle'],
2315
			'location' => $_POST['event_location'],
2316
			'member' => $user_info['id'],
2317
		);
2318
		insertEvent($eventOptions);
2319
	}
2320
	elseif (isset($_POST['calendar']))
2321
	{
2322
		$_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
2323
2324
		// Validate the post...
2325
		require_once($sourcedir . '/Subs-Calendar.php');
2326
		validateEventPost();
2327
2328
		// If you're not allowed to edit any events, you have to be the poster.
2329
		if (!allowedTo('calendar_edit_any'))
2330
		{
2331
			// Get the event's poster.
2332
			$request = $smcFunc['db_query']('', '
2333
				SELECT id_member
2334
				FROM {db_prefix}calendar
2335
				WHERE id_event = {int:id_event}',
2336
				array(
2337
					'id_event' => $_REQUEST['eventid'],
2338
				)
2339
			);
2340
			$row2 = $smcFunc['db_fetch_assoc']($request);
2341
			$smcFunc['db_free_result']($request);
2342
2343
			// Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...)
2344
			isAllowedTo('calendar_edit_' . ($row2['id_member'] == $user_info['id'] ? 'own' : 'any'));
2345
		}
2346
2347
		// Delete it?
2348
		if (isset($_REQUEST['deleteevent']))
2349
			$smcFunc['db_query']('', '
2350
				DELETE FROM {db_prefix}calendar
2351
				WHERE id_event = {int:id_event}',
2352
				array(
2353
					'id_event' => $_REQUEST['eventid'],
2354
				)
2355
			);
2356
		// ... or just update it?
2357
		else
2358
		{
2359
			// Set up our options
2360
			$eventOptions = array(
2361
				'board' => $board,
2362
				'topic' => $topic,
2363
				'title' => $_POST['evtitle'],
2364
				'location' => $_POST['event_location'],
2365
				'member' => $user_info['id'],
2366
			);
2367
			modifyEvent($_REQUEST['eventid'], $eventOptions);
2368
		}
2369
	}
2370
2371
	// Marking read should be done even for editing messages....
2372
	// Mark all the parents read.  (since you just posted and they will be unread.)
2373
	if (!$user_info['is_guest'] && !empty($board_info['parent_boards']))
2374
	{
2375
		$smcFunc['db_query']('', '
2376
			UPDATE {db_prefix}log_boards
2377
			SET id_msg = {int:id_msg}
2378
			WHERE id_member = {int:current_member}
2379
				AND id_board IN ({array_int:board_list})',
2380
			array(
2381
				'current_member' => $user_info['id'],
2382
				'board_list' => array_keys($board_info['parent_boards']),
2383
				'id_msg' => $modSettings['maxMsgID'],
2384
			)
2385
		);
2386
	}
2387
2388
	// Turn notification on or off.  (note this just blows smoke if it's already on or off.)
2389
	if (!empty($_POST['notify']) && !$context['user']['is_guest'])
2390
	{
2391
		$smcFunc['db_insert']('ignore',
2392
			'{db_prefix}log_notify',
2393
			array('id_member' => 'int', 'id_topic' => 'int', 'id_board' => 'int'),
2394
			array($user_info['id'], $topic, 0),
2395
			array('id_member', 'id_topic', 'id_board')
2396
		);
2397
	}
2398
	elseif (!$newTopic)
2399
		$smcFunc['db_query']('', '
2400
			DELETE FROM {db_prefix}log_notify
2401
			WHERE id_member = {int:current_member}
2402
				AND id_topic = {int:current_topic}',
2403
			array(
2404
				'current_member' => $user_info['id'],
2405
				'current_topic' => $topic,
2406
			)
2407
		);
2408
2409
	// Log an act of moderation - modifying.
2410
	if (!empty($moderationAction))
2411
		logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $row['id_member'], 'board' => $board));
2412
2413
	if (isset($_POST['lock']) && $_POST['lock'] != 2)
2414
		logAction(empty($_POST['lock']) ? 'unlock' : 'lock', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
2415
2416
	if (isset($_POST['sticky']))
2417
		logAction(empty($_POST['sticky']) ? 'unsticky' : 'sticky', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
2418
2419
	// Returning to the topic?
2420
	if (!empty($_REQUEST['goback']))
2421
	{
2422
		// Mark the board as read.... because it might get confusing otherwise.
2423
		$smcFunc['db_query']('', '
2424
			UPDATE {db_prefix}log_boards
2425
			SET id_msg = {int:maxMsgID}
2426
			WHERE id_member = {int:current_member}
2427
				AND id_board = {int:current_board}',
2428
			array(
2429
				'current_board' => $board,
2430
				'current_member' => $user_info['id'],
2431
				'maxMsgID' => $modSettings['maxMsgID'],
2432
			)
2433
		);
2434
	}
2435
2436
	if ($board_info['num_topics'] == 0)
2437
		cache_put_data('board-' . $board, null, 120);
2438
2439
	call_integration_hook('integrate_post2_end');
2440
2441
	if (!empty($_POST['announce_topic']) && allowedTo('announce_topic'))
2442
		redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback'));
2443
2444
	if (!empty($_POST['move']) && allowedTo('move_any'))
2445
		redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
2446
2447
	// Return to post if the mod is on.
2448
	if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback']))
2449
		redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], isBrowser('ie'));
2450
	elseif (!empty($_REQUEST['goback']))
2451
		redirectexit('topic=' . $topic . '.new#new', isBrowser('ie'));
2452
	// Dut-dut-duh-duh-DUH-duh-dut-duh-duh!  *dances to the Final Fantasy Fanfare...*
2453
	else
2454
		redirectexit('board=' . $board . '.0');
2455
}
2456
2457
/**
2458
 * Handle the announce topic function (action=announce).
2459
 *
2460
 * checks the topic announcement permissions and loads the announcement template.
2461
 * requires the announce_topic permission.
2462
 * uses the ManageMembers template and Post language file.
2463
 * call the right function based on the sub-action.
2464
 */
2465
function AnnounceTopic()
2466
{
2467
	global $context, $txt, $topic;
2468
2469
	isAllowedTo('announce_topic');
2470
2471
	validateSession();
2472
2473
	if (empty($topic))
2474
		fatal_lang_error('topic_gone', false);
2475
2476
	loadLanguage('Post');
2477
	loadTemplate('Post');
2478
2479
	$subActions = array(
2480
		'selectgroup' => 'AnnouncementSelectMembergroup',
2481
		'send' => 'AnnouncementSend',
2482
	);
2483
2484
	$context['page_title'] = $txt['announce_topic'];
2485
2486
	// Call the function based on the sub-action.
2487
	$call = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'selectgroup';
2488
	call_helper($subActions[$call]);
2489
}
2490
2491
/**
2492
 * Allow a user to chose the membergroups to send the announcement to.
2493
 *
2494
 * lets the user select the membergroups that will receive the topic announcement.
2495
 */
2496
function AnnouncementSelectMembergroup()
2497
{
2498
	global $txt, $context, $topic, $board_info, $smcFunc;
2499
2500
	$groups = array_merge($board_info['groups'], array(1));
2501
	foreach ($groups as $id => $group)
2502
		$groups[$id] = (int) $group;
2503
2504
	$context['groups'] = array();
2505
	if (in_array(0, $groups))
2506
	{
2507
		$context['groups'][0] = array(
2508
			'id' => 0,
2509
			'name' => $txt['announce_regular_members'],
2510
			'member_count' => 'n/a',
2511
		);
2512
	}
2513
2514
	// Get all membergroups that have access to the board the announcement was made on.
2515
	$request = $smcFunc['db_query']('', '
2516
		SELECT mg.id_group, COUNT(mem.id_member) AS num_members
2517
		FROM {db_prefix}membergroups AS mg
2518
			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)
2519
		WHERE mg.id_group IN ({array_int:group_list})
2520
		GROUP BY mg.id_group',
2521
		array(
2522
			'group_list' => $groups,
2523
			'newbie_id_group' => 4,
2524
		)
2525
	);
2526
	while ($row = $smcFunc['db_fetch_assoc']($request))
2527
	{
2528
		$context['groups'][$row['id_group']] = array(
2529
			'id' => $row['id_group'],
2530
			'name' => '',
2531
			'member_count' => $row['num_members'],
2532
		);
2533
	}
2534
	$smcFunc['db_free_result']($request);
2535
2536
	// Now get the membergroup names.
2537
	$request = $smcFunc['db_query']('', '
2538
		SELECT id_group, group_name
2539
		FROM {db_prefix}membergroups
2540
		WHERE id_group IN ({array_int:group_list})',
2541
		array(
2542
			'group_list' => $groups,
2543
		)
2544
	);
2545
	while ($row = $smcFunc['db_fetch_assoc']($request))
2546
		$context['groups'][$row['id_group']]['name'] = $row['group_name'];
2547
	$smcFunc['db_free_result']($request);
2548
2549
	// Get the subject of the topic we're about to announce.
2550
	$request = $smcFunc['db_query']('', '
2551
		SELECT m.subject
2552
		FROM {db_prefix}topics AS t
2553
			INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
2554
		WHERE t.id_topic = {int:current_topic}',
2555
		array(
2556
			'current_topic' => $topic,
2557
		)
2558
	);
2559
	list ($context['topic_subject']) = $smcFunc['db_fetch_row']($request);
2560
	$smcFunc['db_free_result']($request);
2561
2562
	censorText($context['announce_topic']['subject']);
2563
2564
	$context['move'] = isset($_REQUEST['move']) ? 1 : 0;
2565
	$context['go_back'] = isset($_REQUEST['goback']) ? 1 : 0;
2566
2567
	$context['sub_template'] = 'announce';
2568
}
2569
2570
/**
2571
 * Send the announcement in chunks.
2572
 *
2573
 * splits the members to be sent a topic announcement into chunks.
2574
 * composes notification messages in all languages needed.
2575
 * does the actual sending of the topic announcements in chunks.
2576
 * calculates a rough estimate of the percentage items sent.
2577
 */
2578
function AnnouncementSend()
2579
{
2580
	global $topic, $board, $board_info, $context, $modSettings;
2581
	global $language, $scripturl, $sourcedir, $smcFunc;
2582
2583
	checkSession();
2584
2585
	$context['start'] = empty($_REQUEST['start']) ? 0 : (int) $_REQUEST['start'];
2586
	$groups = array_merge($board_info['groups'], array(1));
2587
2588
	if (isset($_POST['membergroups']))
2589
		$_POST['who'] = explode(',', $_POST['membergroups']);
2590
2591
	// Check whether at least one membergroup was selected.
2592
	if (empty($_POST['who']))
2593
		fatal_lang_error('no_membergroup_selected');
2594
2595
	// Make sure all membergroups are integers and can access the board of the announcement.
2596
	foreach ($_POST['who'] as $id => $mg)
2597
		$_POST['who'][$id] = in_array((int) $mg, $groups) ? (int) $mg : 0;
2598
2599
	// Get the topic subject and censor it.
2600
	$request = $smcFunc['db_query']('', '
2601
		SELECT m.id_msg, m.subject, m.body
2602
		FROM {db_prefix}topics AS t
2603
			INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
2604
		WHERE t.id_topic = {int:current_topic}',
2605
		array(
2606
			'current_topic' => $topic,
2607
		)
2608
	);
2609
	list ($id_msg, $context['topic_subject'], $message) = $smcFunc['db_fetch_row']($request);
2610
	$smcFunc['db_free_result']($request);
2611
2612
	censorText($context['topic_subject']);
2613
	censorText($message);
2614
2615
	$message = trim(un_htmlspecialchars(strip_tags(strtr(parse_bbc($message, false, $id_msg), array('<br>' => "\n", '</div>' => "\n", '</li>' => "\n", '&#91;' => '[', '&#93;' => ']')))));
2616
2617
	// We need this in order to be able send emails.
2618
	require_once($sourcedir . '/Subs-Post.php');
2619
2620
	// Select the email addresses for this batch.
2621
	$request = $smcFunc['db_query']('', '
2622
		SELECT mem.id_member, mem.email_address, mem.lngfile
2623
		FROM {db_prefix}members AS mem
2624
		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)
2625
			AND mem.is_activated = {int:is_activated}
2626
			AND mem.id_member > {int:start}
2627
		ORDER BY mem.id_member
2628
		LIMIT {int:chunk_size}',
2629
		array(
2630
			'group_list' => $_POST['who'],
2631
			'is_activated' => 1,
2632
			'start' => $context['start'],
2633
			'additional_group_list' => implode(', mem.additional_groups) != 0 OR FIND_IN_SET(', $_POST['who']),
2634
			// @todo Might need an interface?
2635
			'chunk_size' => 500,
2636
		)
2637
	);
2638
2639
	// All members have received a mail. Go to the next screen.
2640
	if ($smcFunc['db_num_rows']($request) == 0)
2641
	{
2642
		logAction('announce_topic', array('topic' => $topic), 'user');
2643
		if (!empty($_REQUEST['move']) && allowedTo('move_any'))
2644
			redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
2645
		elseif (!empty($_REQUEST['goback']))
2646
			redirectexit('topic=' . $topic . '.new;boardseen#new', isBrowser('ie'));
2647
		else
2648
			redirectexit('board=' . $board . '.0');
2649
	}
2650
2651
	$announcements = array();
2652
	// Loop through all members that'll receive an announcement in this batch.
2653
	$rows = array();
2654
	while ($row = $smcFunc['db_fetch_assoc']($request))
2655
	{
2656
		$rows[$row['id_member']] = $row;
2657
	}
2658
	$smcFunc['db_free_result']($request);
2659
2660
	// Load their alert preferences
2661
	require_once($sourcedir . '/Subs-Notify.php');
2662
	$prefs = getNotifyPrefs(array_keys($rows), 'announcements', true);
2663
2664
	foreach ($rows as $row)
2665
	{
2666
		$context['start'] = $row['id_member'];
2667
		// Force them to have it?
2668
		if (empty($prefs[$row['id_member']]['announcements']))
2669
			continue;
2670
2671
		$cur_language = empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'];
2672
2673
		// If the language wasn't defined yet, load it and compose a notification message.
2674
		if (!isset($announcements[$cur_language]))
2675
		{
2676
			$replacements = array(
2677
				'TOPICSUBJECT' => $context['topic_subject'],
2678
				'MESSAGE' => $message,
2679
				'TOPICLINK' => $scripturl . '?topic=' . $topic . '.0',
2680
			);
2681
2682
			$emaildata = loadEmailTemplate('new_announcement', $replacements, $cur_language);
2683
2684
			$announcements[$cur_language] = array(
2685
				'subject' => $emaildata['subject'],
2686
				'body' => $emaildata['body'],
2687
				'is_html' => $emaildata['is_html'],
2688
				'recipients' => array(),
2689
			);
2690
		}
2691
2692
		$announcements[$cur_language]['recipients'][$row['id_member']] = $row['email_address'];
2693
	}
2694
2695
	// For each language send a different mail - low priority...
2696
	foreach ($announcements as $lang => $mail)
2697
		sendmail($mail['recipients'], $mail['subject'], $mail['body'], null, 'ann-' . $lang, $mail['is_html'], 5);
2698
2699
	$context['percentage_done'] = round(100 * $context['start'] / $modSettings['latestMember'], 1);
2700
2701
	$context['move'] = empty($_REQUEST['move']) ? 0 : 1;
2702
	$context['go_back'] = empty($_REQUEST['goback']) ? 0 : 1;
2703
	$context['membergroups'] = implode(',', $_POST['who']);
2704
	$context['sub_template'] = 'announcement_send';
2705
2706
	// Go back to the correct language for the user ;).
2707
	if (!empty($modSettings['userLanguage']))
2708
		loadLanguage('Post');
2709
}
2710
2711
/**
2712
 * Get the topic for display purposes.
2713
 *
2714
 * gets a summary of the most recent posts in a topic.
2715
 * depends on the topicSummaryPosts setting.
2716
 * if you are editing a post, only shows posts previous to that post.
2717
 */
2718
function getTopic()
2719
{
2720
	global $topic, $modSettings, $context, $smcFunc, $counter, $options;
2721
2722
	if (isset($_REQUEST['xml']))
2723
		$limit = '
2724
		LIMIT ' . (empty($context['new_replies']) ? '0' : $context['new_replies']);
2725
	else
2726
		$limit = empty($modSettings['topicSummaryPosts']) ? '' : '
2727
		LIMIT ' . (int) $modSettings['topicSummaryPosts'];
2728
2729
	// If you're modifying, get only those posts before the current one. (otherwise get all.)
2730
	$request = $smcFunc['db_query']('', '
2731
		SELECT
2732
			COALESCE(mem.real_name, m.poster_name) AS poster_name, m.poster_time,
2733
			m.body, m.smileys_enabled, m.id_msg, m.id_member
2734
		FROM {db_prefix}messages AS m
2735
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
2736
		WHERE m.id_topic = {int:current_topic}' . (isset($_REQUEST['msg']) ? '
2737
			AND m.id_msg < {int:id_msg}' : '') . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
2738
			AND m.approved = {int:approved}') . '
2739
		ORDER BY m.id_msg DESC' . $limit,
2740
		array(
2741
			'current_topic' => $topic,
2742
			'id_msg' => isset($_REQUEST['msg']) ? (int) $_REQUEST['msg'] : 0,
2743
			'approved' => 1,
2744
		)
2745
	);
2746
	$context['previous_posts'] = array();
2747
	while ($row = $smcFunc['db_fetch_assoc']($request))
2748
	{
2749
		// Censor, BBC, ...
2750
		censorText($row['body']);
2751
		$row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']);
2752
2753
		// ...and store.
2754
		$context['previous_posts'][] = array(
2755
			'counter' => $counter++,
2756
			'poster' => $row['poster_name'],
2757
			'message' => $row['body'],
2758
			'time' => timeformat($row['poster_time']),
2759
			'timestamp' => forum_time(true, $row['poster_time']),
2760
			'id' => $row['id_msg'],
2761
			'is_new' => !empty($context['new_replies']),
2762
			'is_ignored' => !empty($modSettings['enable_buddylist']) && !empty($options['posts_apply_ignore_list']) && in_array($row['id_member'], $context['user']['ignoreusers']),
2763
		);
2764
2765
		if (!empty($context['new_replies']))
2766
			$context['new_replies']--;
2767
	}
2768
	$smcFunc['db_free_result']($request);
2769
}
2770
2771
/**
2772
 * Loads a post an inserts it into the current editing text box.
2773
 * uses the Post language file.
2774
 * uses special (sadly browser dependent) javascript to parse entities for internationalization reasons.
2775
 * accessed with ?action=quotefast.
2776
 */
2777
function QuoteFast()
2778
{
2779
	global $modSettings, $user_info, $context;
2780
	global $sourcedir, $smcFunc;
2781
2782
	loadLanguage('Post');
2783
	if (!isset($_REQUEST['xml']))
2784
		loadTemplate('Post');
2785
2786
	include_once($sourcedir . '/Subs-Post.php');
2787
2788
	$moderate_boards = boardsAllowedTo('moderate_board');
2789
2790
	$request = $smcFunc['db_query']('', '
2791
		SELECT COALESCE(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.body, m.id_topic, m.subject,
2792
			m.id_board, m.id_member, m.approved, m.modified_time, m.modified_name, m.modified_reason
2793
		FROM {db_prefix}messages AS m
2794
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
2795
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
2796
		WHERE {query_see_message_board}
2797
			AND m.id_msg = {int:id_msg}' . (isset($_REQUEST['modify']) || (!empty($moderate_boards) && $moderate_boards[0] == 0) ? '' : '
2798
			AND (t.locked = {int:not_locked}' . (empty($moderate_boards) ? '' : ' OR m.id_board IN ({array_int:moderation_board_list})') . ')') . '
2799
		LIMIT 1',
2800
		array(
2801
			'current_member' => $user_info['id'],
2802
			'moderation_board_list' => $moderate_boards,
2803
			'id_msg' => (int) $_REQUEST['quote'],
2804
			'not_locked' => 0,
2805
		)
2806
	);
2807
	$context['close_window'] = $smcFunc['db_num_rows']($request) == 0;
2808
	$row = $smcFunc['db_fetch_assoc']($request);
2809
	$smcFunc['db_free_result']($request);
2810
2811
	$context['sub_template'] = 'quotefast';
2812
	if (!empty($row))
2813
		$can_view_post = $row['approved'] || ($row['id_member'] != 0 && $row['id_member'] == $user_info['id']) || allowedTo('approve_posts', $row['id_board']);
2814
2815
	if (!empty($can_view_post))
2816
	{
2817
		// Remove special formatting we don't want anymore.
2818
		$row['body'] = un_preparsecode($row['body']);
2819
2820
		// Censor the message!
2821
		censorText($row['body']);
2822
2823
		// Want to modify a single message by double clicking it?
2824
		if (isset($_REQUEST['modify']))
2825
		{
2826
			censorText($row['subject']);
2827
2828
			$context['sub_template'] = 'modifyfast';
2829
			$context['message'] = array(
2830
				'id' => $_REQUEST['quote'],
2831
				'body' => $row['body'],
2832
				'subject' => addcslashes($row['subject'], '"'),
2833
				'reason' => array(
2834
					'name' => $row['modified_name'],
2835
					'text' => $row['modified_reason'],
2836
					'time' => $row['modified_time'],
2837
				),
2838
			);
2839
2840
			return;
2841
		}
2842
2843
		// Remove any nested quotes.
2844
		if (!empty($modSettings['removeNestedQuotes']))
2845
			$row['body'] = preg_replace(array('~\n?\[quote.*?\].+?\[/quote\]\n?~is', '~^\n~', '~\[/quote\]~'), '', $row['body']);
2846
2847
		$lb = "\n";
2848
2849
		// Add a quote string on the front and end.
2850
		$context['quote']['xml'] = '[quote author=' . $row['poster_name'] . ' link=msg=' . (int) $_REQUEST['quote'] . ' date=' . $row['poster_time'] . ']' . $lb . $row['body'] . $lb . '[/quote]';
2851
		$context['quote']['text'] = strtr(un_htmlspecialchars($context['quote']['xml']), array('\'' => '\\\'', '\\' => '\\\\', "\n" => '\\n', '</script>' => '</\' + \'script>'));
2852
		$context['quote']['xml'] = strtr($context['quote']['xml'], array('&nbsp;' => '&#160;', '<' => '&lt;', '>' => '&gt;'));
2853
2854
		$context['quote']['mozilla'] = strtr($smcFunc['htmlspecialchars']($context['quote']['text']), array('&quot;' => '"'));
2855
	}
2856
	//@todo Needs a nicer interface.
2857
	// In case our message has been removed in the meantime.
2858
	elseif (isset($_REQUEST['modify']))
2859
	{
2860
		$context['sub_template'] = 'modifyfast';
2861
		$context['message'] = array(
2862
			'id' => 0,
2863
			'body' => '',
2864
			'subject' => '',
2865
			'reason' => array(
2866
				'name' => '',
2867
				'text' => '',
2868
				'time' => '',
2869
			),
2870
		);
2871
	}
2872
	else
2873
		$context['quote'] = array(
2874
			'xml' => '',
2875
			'mozilla' => '',
2876
			'text' => '',
2877
		);
2878
}
2879
2880
/**
2881
 * Used to edit the body or subject of a message inline
2882
 * called from action=jsmodify from script and topic js
2883
 */
2884
function JavaScriptModify()
2885
{
2886
	global $sourcedir, $modSettings, $board, $topic, $txt;
2887
	global $user_info, $context, $smcFunc, $language, $board_info;
2888
2889
	// We have to have a topic!
2890
	if (empty($topic))
2891
		obExit(false);
2892
2893
	checkSession('get');
2894
	require_once($sourcedir . '/Subs-Post.php');
2895
2896
	// Assume the first message if no message ID was given.
2897
	$request = $smcFunc['db_query']('', '
2898
		SELECT
2899
			t.locked, t.num_replies, t.id_member_started, t.id_first_msg,
2900
			m.id_msg, m.id_member, m.poster_time, m.subject, m.smileys_enabled, m.body, m.icon,
2901
			m.modified_time, m.modified_name, m.modified_reason, m.approved,
2902
			m.poster_name, m.poster_email
2903
		FROM {db_prefix}messages AS m
2904
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
2905
		WHERE m.id_msg = {raw:id_msg}
2906
			AND m.id_topic = {int:current_topic}' . (allowedTo('modify_any') || allowedTo('approve_posts') ? '' : (!$modSettings['postmod_active'] ? '
2907
			AND (m.id_member != {int:guest_id} AND m.id_member = {int:current_member})' : '
2908
			AND (m.approved = {int:is_approved} OR (m.id_member != {int:guest_id} AND m.id_member = {int:current_member}))')),
2909
		array(
2910
			'current_member' => $user_info['id'],
2911
			'current_topic' => $topic,
2912
			'id_msg' => empty($_REQUEST['msg']) ? 't.id_first_msg' : (int) $_REQUEST['msg'],
2913
			'is_approved' => 1,
2914
			'guest_id' => 0,
2915
		)
2916
	);
2917
	if ($smcFunc['db_num_rows']($request) == 0)
2918
		fatal_lang_error('no_board', false);
2919
	$row = $smcFunc['db_fetch_assoc']($request);
2920
	$smcFunc['db_free_result']($request);
2921
2922
	// Change either body or subject requires permissions to modify messages.
2923
	if (isset($_POST['message']) || isset($_POST['subject']) || isset($_REQUEST['icon']))
2924
	{
2925
		if (!empty($row['locked']))
2926
			isAllowedTo('moderate_board');
2927
2928
		if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
2929
		{
2930
			if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
2931
				fatal_lang_error('modify_post_time_passed', false);
2932
			elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_own'))
2933
				isAllowedTo('modify_replies');
2934
			else
2935
				isAllowedTo('modify_own');
2936
		}
2937
		// Otherwise, they're locked out; someone who can modify the replies is needed.
2938
		elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_any'))
2939
			isAllowedTo('modify_replies');
2940
		else
2941
			isAllowedTo('modify_any');
2942
2943
		// Only log this action if it wasn't your message.
2944
		$moderationAction = $row['id_member'] != $user_info['id'];
2945
	}
2946
2947
	$post_errors = array();
2948
	if (isset($_POST['subject']) && $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['subject'])) !== '')
2949
	{
2950
		$_POST['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
2951
2952
		// Maximum number of characters.
2953
		if ($smcFunc['strlen']($_POST['subject']) > 100)
2954
			$_POST['subject'] = $smcFunc['substr']($_POST['subject'], 0, 100);
2955
	}
2956
	elseif (isset($_POST['subject']))
2957
	{
2958
		$post_errors[] = 'no_subject';
2959
		unset($_POST['subject']);
2960
	}
2961
2962
	if (isset($_POST['message']))
2963
	{
2964
		if ($smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['message'])) === '')
2965
		{
2966
			$post_errors[] = 'no_message';
2967
			unset($_POST['message']);
2968
		}
2969
		elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_POST['message']) > $modSettings['max_messageLength'])
2970
		{
2971
			$post_errors[] = 'long_message';
2972
			unset($_POST['message']);
2973
		}
2974
		else
2975
		{
2976
			$_POST['message'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
2977
2978
			preparsecode($_POST['message']);
2979
2980
			if ($smcFunc['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), implode('', $context['allowed_html_tags']))) === '')
2981
			{
2982
				$post_errors[] = 'no_message';
2983
				unset($_POST['message']);
2984
			}
2985
		}
2986
	}
2987
2988
	if (isset($_POST['lock']))
2989
	{
2990
		if (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $row['id_member']))
2991
			unset($_POST['lock']);
2992
		elseif (!allowedTo('lock_any'))
2993
		{
2994
			if ($row['locked'] == 1)
2995
				unset($_POST['lock']);
2996
			else
2997
				$_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
2998
		}
2999
		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...
3000
			unset($_POST['lock']);
3001
		else
3002
			$_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
3003
	}
3004
3005
	if (isset($_POST['sticky']) && !allowedTo('make_sticky'))
3006
		unset($_POST['sticky']);
3007
3008
	if (isset($_POST['modify_reason']))
3009
	{
3010
		$_POST['modify_reason'] = strtr($smcFunc['htmlspecialchars']($_POST['modify_reason']), array("\r" => '', "\n" => '', "\t" => ''));
3011
3012
		// Maximum number of characters.
3013
		if ($smcFunc['strlen']($_POST['modify_reason']) > 100)
3014
			$_POST['modify_reason'] = $smcFunc['substr']($_POST['modify_reason'], 0, 100);
3015
	}
3016
3017
	if (empty($post_errors))
3018
	{
3019
		$msgOptions = array(
3020
			'id' => $row['id_msg'],
3021
			'subject' => isset($_POST['subject']) ? $_POST['subject'] : null,
3022
			'body' => isset($_POST['message']) ? $_POST['message'] : null,
3023
			'icon' => isset($_REQUEST['icon']) ? preg_replace('~[\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : null,
3024
			'modify_reason' => (isset($_POST['modify_reason']) ? $_POST['modify_reason'] : ''),
3025
		);
3026
		$topicOptions = array(
3027
			'id' => $topic,
3028
			'board' => $board,
3029
			'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null,
3030
			'sticky_mode' => isset($_POST['sticky']) ? (int) $_POST['sticky'] : null,
3031
			'mark_as_read' => true,
3032
		);
3033
		$posterOptions = array(
3034
			'id' => $user_info['id'],
3035
			'name' => $row['poster_name'],
3036
			'email' => $row['poster_email'],
3037
			'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count'],
3038
		);
3039
3040
		// Only consider marking as editing if they have edited the subject, message or icon.
3041
		if ((isset($_POST['subject']) && $_POST['subject'] != $row['subject']) || (isset($_POST['message']) && $_POST['message'] != $row['body']) || (isset($_REQUEST['icon']) && $_REQUEST['icon'] != $row['icon']))
3042
		{
3043
			// And even then only if the time has passed...
3044
			if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member'])
3045
			{
3046
				$msgOptions['modify_time'] = time();
3047
				$msgOptions['modify_name'] = $user_info['name'];
3048
			}
3049
		}
3050
		// If nothing was changed there's no need to add an entry to the moderation log.
3051
		else
3052
			$moderationAction = false;
3053
3054
		modifyPost($msgOptions, $topicOptions, $posterOptions);
3055
3056
		// If we didn't change anything this time but had before put back the old info.
3057
		if (!isset($msgOptions['modify_time']) && !empty($row['modified_time']))
3058
		{
3059
			$msgOptions['modify_time'] = $row['modified_time'];
3060
			$msgOptions['modify_name'] = $row['modified_name'];
3061
			$msgOptions['modify_reason'] = $row['modified_reason'];
3062
		}
3063
3064
		// Changing the first subject updates other subjects to 'Re: new_subject'.
3065
		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'))))
3066
		{
3067
			// Get the proper (default language) response prefix first.
3068
			if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix')))
3069
			{
3070
				if ($language === $user_info['language'])
3071
					$context['response_prefix'] = $txt['response_prefix'];
3072
				else
3073
				{
3074
					loadLanguage('index', $language, false);
3075
					$context['response_prefix'] = $txt['response_prefix'];
3076
					loadLanguage('index');
3077
				}
3078
				cache_put_data('response_prefix', $context['response_prefix'], 600);
3079
			}
3080
3081
			$smcFunc['db_query']('', '
3082
				UPDATE {db_prefix}messages
3083
				SET subject = {string:subject}
3084
				WHERE id_topic = {int:current_topic}
3085
					AND id_msg != {int:id_first_msg}',
3086
				array(
3087
					'current_topic' => $topic,
3088
					'id_first_msg' => $row['id_first_msg'],
3089
					'subject' => $context['response_prefix'] . $_POST['subject'],
3090
				)
3091
			);
3092
		}
3093
3094
		if (!empty($moderationAction))
3095
			logAction('modify', array('topic' => $topic, 'message' => $row['id_msg'], 'member' => $row['id_member'], 'board' => $board));
3096
	}
3097
3098
	if (isset($_REQUEST['xml']))
3099
	{
3100
		$context['sub_template'] = 'modifydone';
3101
		if (empty($post_errors) && isset($msgOptions['subject']) && isset($msgOptions['body']))
3102
		{
3103
			$context['message'] = array(
3104
				'id' => $row['id_msg'],
3105
				'modified' => array(
3106
					'time' => isset($msgOptions['modify_time']) ? timeformat($msgOptions['modify_time']) : '',
3107
					'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0,
3108
					'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : '',
3109
					'reason' => $msgOptions['modify_reason'],
3110
				),
3111
				'subject' => $msgOptions['subject'],
3112
				'first_in_topic' => $row['id_msg'] == $row['id_first_msg'],
3113
				'body' => strtr($msgOptions['body'], array(']]>' => ']]]]><![CDATA[>')),
3114
			);
3115
3116
			censorText($context['message']['subject']);
3117
			censorText($context['message']['body']);
3118
3119
			$context['message']['body'] = parse_bbc($context['message']['body'], $row['smileys_enabled'], $row['id_msg']);
3120
		}
3121
		// Topic?
3122
		elseif (empty($post_errors))
3123
		{
3124
			$context['sub_template'] = 'modifytopicdone';
3125
			$context['message'] = array(
3126
				'id' => $row['id_msg'],
3127
				'modified' => array(
3128
					'time' => isset($msgOptions['modify_time']) ? timeformat($msgOptions['modify_time']) : '',
3129
					'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0,
3130
					'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : '',
3131
				),
3132
				'subject' => isset($msgOptions['subject']) ? $msgOptions['subject'] : '',
3133
			);
3134
3135
			censorText($context['message']['subject']);
3136
		}
3137
		else
3138
		{
3139
			$context['message'] = array(
3140
				'id' => $row['id_msg'],
3141
				'errors' => array(),
3142
				'error_in_subject' => in_array('no_subject', $post_errors),
3143
				'error_in_body' => in_array('no_message', $post_errors) || in_array('long_message', $post_errors),
3144
			);
3145
3146
			loadLanguage('Errors');
3147
			foreach ($post_errors as $post_error)
3148
			{
3149
				if ($post_error == 'long_message')
3150
					$context['message']['errors'][] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']);
3151
				else
3152
					$context['message']['errors'][] = $txt['error_' . $post_error];
3153
			}
3154
		}
3155
	}
3156
	else
3157
		obExit(false);
3158
}
3159
3160
?>