Issues (1061)

Sources/Post.php (1 issue)

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