Completed
Pull Request — development (#2528)
by Thorsten
15:29
created

Emailpost.controller.php ➔ pbe_create_post()   F

Complexity

Conditions 31
Paths 1449

Size

Total Lines 85
Code Lines 52

Duplication

Lines 17
Ratio 20 %

Code Coverage

Tests 0
CRAP Score 992
Metric Value
cc 31
eloc 52
nc 1449
nop 3
dl 17
loc 85
rs 2.2231
ccs 0
cts 64
cp 0
crap 992

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 23 and the first side effect is on line 14.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
/**
4
 * All the functions that validate and then save an email as a post or pm
5
 *
6
 * @name      ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
9
 *
10
 * @version 1.1 beta 1
11
 *
12
 */
13
14
if (!defined('ELK'))
15
	die('No access...');
16
17
/**
18
 * Emailpost_Controller class.
19
 * Handles items pertaining to posting or PM an item that was received by email
20
 *
21
 * @package Maillist
22
 */
23
class Emailpost_Controller extends Action_Controller
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
24
{
25
	/**
26
	 * Default entry point, it forwards to a worker method,
27
	 * if we ever get here.
28
	 * @see Action_Controller::action_index()
29
	 */
30
	public function action_index()
31
	{
32
		// By default we go to preview
33
		$this->action_pbe_preview();
34
	}
35
36
	/**
37
	 * Main email posting controller, reads, parses, checks and posts an email message or PM
38
	 *
39
	 * What it does:
40
	 * - Allows a user to reply to a topic on the board by emailing a reply to a
41
	 * notification message.
42
	 * - It must have the security key in the email or it will be rejected
43
	 * - It must be from the email of a registered user
44
	 * - The key must have been sent to that user
45
	 * - Keys are used once and then discarded
46
	 * - Accessed by email imap cron script, and ManageMaillist.controller.php.
47
	 *
48
	 * @param string|null $data used to supply a full headers+body email
49
	 * @param boolean $force used to override common failure errors
50
	 * @param string|null $key used to supply a lost key
51
	 */
52
	public function action_pbe_post($data = null, $force = false, $key = null)
53
	{
54
		global $txt, $modSettings, $language, $user_info, $maintenance;
55
56
		// The function is not even on ...
57
		if (empty($modSettings['maillist_enabled']))
58
			return false;
59
60
		// Our mail parser and our main subs
61
		require_once(SUBSDIR . '/Emailpost.subs.php');
62
63
		// Init
64
		loadLanguage('Maillist');
65
		setMemoryLimit('128M');
66
67
		// Load the email parser and get some data to work with
68
		$email_message = new Email_Parse();
69
		$email_message->read_data($data, BOARDDIR);
70
		if (!$email_message->raw_message)
71
			return false;
72
73
		// Ask for an html version (if available) and some needed details
74
		$email_message->read_email(true, $email_message->raw_message);
75
		$email_message->load_address();
76
		$email_message->load_key($key);
77
78
		// Check if it's a DSN, and handle it
79 View Code Duplication
		if ($email_message->_is_dsn)
80
		{
81
			if (!empty($modSettings['pbe_bounce_detect']))
82
			{
83
				pbe_disable_user_notify($email_message);
84
85
				// @todo Notify the user
86
				if (!empty($modSettings['pbe_bounce_record']))
87
				{
88
					// They can record the message anyway, if they so wish
89
					return pbe_emailError('error_bounced', $email_message);
90
				}
91
92
				// If they don't wish, then return false like recording the failure would do
93
				return false;
94
			}
95
			else
96
			{
97
				// When the auto-disable function is not turned on, record the DSN
98
				// In the failed email table for the admins to handle however
99
				return pbe_emailError('error_bounced', $email_message);
100
			}
101
		}
102
103
		// If the feature is on but the post/pm function is not enabled, just log the message.
104
		if (empty($modSettings['pbe_post_enabled']) && empty($modSettings['pbe_pm_enabled']))
105
			return pbe_emailError('error_email_notenabled', $email_message);
106
107
		// Spam I am?
108
		if ($email_message->load_spam() && !$force)
109
			return pbe_emailError('error_found_spam', $email_message);
110
111
		// Load the user from the database based on the sending email address
112
		$email_message->email['from'] = !empty($email_message->email['from']) ? strtolower($email_message->email['from']) : '';
113
		$pbe = query_load_user_info($email_message->email['from']);
114
115
		// Can't find this email in our database, a non-user, a spammer, a looser, a poser or even worse?
116
		if (empty($pbe))
117
			return pbe_emailError('error_not_find_member', $email_message);
118
119
		// Find the message security key, without it we are not going anywhere ever
120
		if (empty($email_message->message_key_id))
121
			return pbe_emailError('error_missing_key', $email_message);
122
123
		// Good we have a key, who was it sent to?
124
		$key_owner = query_key_owner($email_message);
125
126
		// Can't find this key in the database, either
127
		// a) spam attempt or b) replying with an expired/consumed key
128
		if (empty($key_owner) && !$force)
129
			return pbe_emailError('error_' . ($email_message->message_type === 'p' ? 'pm_' : '') . 'not_find_entry', $email_message);
130
131
		// The key received was not sent to this member ... how we love those email aggregators
132
		if (strtolower($key_owner) !== $email_message->email['from'] && !$force)
133
			return pbe_emailError('error_key_sender_match', $email_message);
134
135
		// In maintenance mode, just log it for now
136 View Code Duplication
		if (!empty($maintenance) && $maintenance !== 2 && !$pbe['user_info']['is_admin'] && !$user_info['is_admin'])
137
			return pbe_emailError('error_in_maintenance_mode', $email_message);
138
139
		// The email looks valid, now on to check the actual user trying to make the post/pm
140
		// lets load the topic/message info and any additional permissions we need
141
		$topic_info = array();
142
		$pm_info = array();
143
		if ($email_message->message_type === 't' || $email_message->message_type === 'm')
144
		{
145
			// Load the message/topic details
146
			$topic_info = query_load_message($email_message->message_type, $email_message->message_id, $pbe);
147
			if (empty($topic_info))
148
				return pbe_emailError('error_topic_gone', $email_message);
149
150
			// Load board permissions
151
			query_load_permissions('board', $pbe, $topic_info);
152
		}
153
		else
154
		{
155
			// Load the PM details
156
			$pm_info = query_load_message($email_message->message_type, $email_message->message_id, $pbe);
157
			if (empty($pm_info))
158
			{
159
				// Duh oh ... likely they deleted the PM on the site and are now
160
				// replying to the PM by email, the agony!
161
				return pbe_emailError('error_pm_not_found', $email_message);
162
			}
163
		}
164
165
		// Account for moderation actions
166
		pbe_check_moderation($pbe);
167
168
		// Maybe they want to do additional spam / security checking
169
		call_integration_hook('integrate_mailist_checks_before', array($email_message, $pbe));
170
171
		// Load in the correct Re: for the language
172
		if ($language === $pbe['user_info']['language'])
173
			$pbe['response_prefix'] = $txt['response_prefix'];
174
		else
175
		{
176
			loadLanguage('index', $language, false);
177
			$pbe['response_prefix'] = $txt['response_prefix'];
178
			loadLanguage('index');
179
		}
180
181
		// Allow for new topics to be started via a email subject change
182
		if (!empty($modSettings['maillist_newtopic_change']) && ($email_message->message_type === 'm'))
183
		{
184
			$subject = str_replace($pbe['response_prefix'], '', pbe_clean_email_subject($email_message->subject));
185
			$current_subject = str_replace($pbe['response_prefix'], '', $topic_info['subject']);
186
187
			// If it does not match, then we go to make a new topic instead
188
			if (trim($subject) != trim($current_subject))
189
			{
190
				$board_info = query_load_board_details($topic_info['id_board'], $pbe);
191
				return pbe_create_topic($pbe, $email_message, $board_info);
192
			}
193
		}
194
195
		// Time to make a Post or a PM, first up topic and message replies
196
		if ($email_message->message_type === 't' || $email_message->message_type === 'm')
197
			$result = pbe_create_post($pbe, $email_message, $topic_info);
198
		// Must be a PM then
199
		elseif ($email_message->message_type === 'p')
200
			$result = pbe_create_pm($pbe, $email_message, $pm_info);
201
202
		if (!empty($result))
203
		{
204
			// We have now posted or PM'ed .. lets do some database maintenance cause maintenance is fun :'(
205
			query_key_maintenance($email_message);
206
207
			// Update this user so the log shows they were/are active, no lurking in the email ether
208
			query_update_member_stats($pbe, $email_message, $email_message->message_type === 'p' ? $pm_info : $topic_info);
209
		}
210
211
		return !empty($result);
212
	}
213
214
	/**
215
	 * New Topic posting controller, reads, parses, checks and posts a new topic
216
	 *
217
	 * What it does:
218
	 * - New topics do not have security keys in them so they are subject to spoofing
219
	 * - It must be from the email of a registered user
220
	 * - It must have been sent to an email ID that has been set to post new topics
221
	 * - Accessed through emailtopic.
222
	 *
223
	 * @param string|null $data used to supply a full body+headers email
224
	 */
225
	public function action_pbe_topic($data = null)
226
	{
227
		global $modSettings, $user_info, $maintenance;
228
229
		// The function is not even on ...
230
		if (empty($modSettings['maillist_enabled']))
231
			return false;
232
233
		// Our mail parser and our main subs
234
		require_once(SUBSDIR . '/Emailpost.subs.php');
235
236
		// Init
237
		loadLanguage('Maillist');
238
		setMemoryLimit('256M');
239
240
		// Get the data from one of our sources
241
		$email_message = new Email_Parse();
242
		$email_message->read_data($data, BOARDDIR);
243
		if (!$email_message->raw_message)
244
			return false;
245
246
		// Parse the header and some needed details
247
		$email_message->read_email(true, $email_message->raw_message);
248
		$email_message->load_address();
249
250
		// No key for this, so set some blanks for the error function (if needed)
251
		$email_message->message_type = 'x';
252
		$email_message->message_key_id = '';
253
		$email_message->message_key = '';
254
		$email_message->message_id = '0';
255
256
		// Check if it's a DSN
257
		// Hopefully, this will eventually DO something but for now
258
		// we'll just add it with a more specific error reason
259 View Code Duplication
		if ($email_message->_is_dsn)
260
		{
261
			if (!empty($modSettings['pbe_bounce_detect']))
262
			{
263
				pbe_disable_user_notify($email_message);
264
265
				// @todo Notify the user
266
				if (!empty($modSettings['pbe_bounce_record']))
267
				{
268
					// They can record the message anyway, if they so wish
269
					return pbe_emailError('error_bounced', $email_message);
270
				}
271
272
				// If they don't wish, then return false like recording the failure
273
				return false;
274
			}
275
			else
276
			{
277
				// When the auto-disable function is not turned on, record the DSN
278
				// In the failed email table for the admins to handle however
279
				return pbe_emailError('error_bounced', $email_message);
280
			}
281
		}
282
283
		// If the feature is on but the post/pm function is not enabled, just log the message.
284
		if (empty($modSettings['pbe_post_enabled']))
285
			return pbe_emailError('error_email_notenabled', $email_message);
286
287
		// Load the user from the database based on the sending email address
288
		$email_message->email['from'] = !empty($email_message->email['from']) ? strtolower($email_message->email['from']) : '';
289
		$pbe = query_load_user_info($email_message->email['from']);
290
291
		// Can't find this email as one of our users?
292
		if (empty($pbe))
293
			return pbe_emailError('error_not_find_member', $email_message);
294
295
		// Getting hammy with it?
296
		if ($email_message->load_spam())
297
			return pbe_emailError('error_found_spam', $email_message);
298
299
		// The board that this email address corresponds to
300
		$board_number = pbe_find_board_number($email_message);
301
		if (empty($board_number))
302
			return pbe_emailError('error_not_find_board', $email_message);
303
304
		// In maintenance mode so just save it for the moderators to deal with
305 View Code Duplication
		if (!empty($maintenance) && $maintenance !== 2 && !$pbe['user_info']['is_admin'] && !$user_info['is_admin'])
306
			return pbe_emailError('error_in_maintenance_mode', $email_message);
307
308
		// Any additional spam / security checking
309
		call_integration_hook('integrate_mailist_checks_before', array($email_message, $pbe));
310
311
		// To post a NEW topic, we need some board details for where it goes
312
		$board_info = query_load_board_details($board_number, $pbe);
313
		if (empty($board_info))
314
			return pbe_emailError('error_board_gone', $email_message);
315
316
		// Load up this users permissions for that board
317
		query_load_permissions('board', $pbe, $board_info);
318
319
		// Account for any moderation they may be under
320
		pbe_check_moderation($pbe);
321
322
		// Create the topic, send notifications
323
		return pbe_create_topic($pbe, $email_message, $board_info);
324
	}
325
326
	/**
327
	 * Used to preview a failed email from the ACP
328
	 *
329
	 * What it does:
330
	 * - Called from ManageMaillist.controller, which checks topic/message permission for viewing
331
	 * - Calls pbe_load_text to prepare text for the preview
332
	 * - Returns an array of values for use in the template
333
	 *
334
	 * @param string $data raw email string, including headers
335
	 * @return boolean
336
	 */
337
	public function action_pbe_preview($data = '')
338
	{
339
		global $txt, $modSettings;
340
341
		// Our mail parser and our main subs
342
		require_once(SUBSDIR . '/Emailpost.subs.php');
343
344
		// Init
345
		$pbe = array();
346
		loadLanguage('Maillist');
347
348
		// Load the email parser and get some data to work with
349
		$email_message = new Email_Parse();
350
		$email_message->read_data($data, BOARDDIR);
351
		if (!$email_message->raw_message)
352
			return false;
353
354
		// Ask for an html version (if available) and some needed details
355
		$email_message->read_email(true, $email_message->raw_message);
356
		$html = $email_message->html_found;
357
		$email_message->load_address();
358
		$email_message->load_key();
359
360
		// Convert to BBC and Format for the preview
361
		$text = pbe_load_text($html, $email_message, $pbe);
362
363
		// If there are attachments, just get the count
364
		$attachment_count = 0;
365
		if (!empty($email_message->attachments) && !empty($modSettings['maillist_allow_attachments']) && !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1)
366
		{
367
			if ($email_message->message_type === 'p')
368
				$text .= "\n\n" . $txt['error_no_pm_attach'] . "\n";
369
			else
370
				$attachment_count = count($email_message->attachments);
371
		}
372
373
		if ($attachment_count)
374
			$text .= "\n\n" . sprintf($txt['email_attachments'], $attachment_count);
375
376
		// Return the parsed and formatted body and who it was sent to for the template
377
		return array('body' => $text, 'to' => implode(' & ', $email_message->email['to']) . (!empty($email_message->email['cc']) ? ', ' . implode(' & ', $email_message->email['cc']) : ''));
378
	}
379
}
380
381
/**
382
 * Attempts to create a reply post on the forum
383
 *
384
 * What it does:
385
 * - Checks if the user has permissions to post/reply/postby email
386
 * - Calls pbe_load_text to prepare text for the post
387
 * - returns true if successful or false for any number of failures
388
 *
389
 * @package Maillist
390
 * @param mixed[] $pbe array of all pbe user_info values
391
 * @param Email_Parse $email_message
392
 * @param mixed[] $topic_info
393
 */
394
function pbe_create_post($pbe, $email_message, $topic_info)
395
{
396
	global $modSettings, $txt;
397
398
	// Validate they have permission to reply
399
	$becomesApproved = true;
400
	if (!in_array('postby_email', $pbe['user_info']['permissions']))
401
		return pbe_emailError('error_permission', $email_message);
402 View Code Duplication
	elseif ($topic_info['locked'] && !$pbe['user_info']['is_admin'] && !in_array('moderate_forum', $pbe['user_info']['permissions']))
403
		return pbe_emailError('error_locked', $email_message);
404
	elseif ($topic_info['id_member_started'] === $pbe['profile']['id_member'] && !$pbe['user_info']['is_admin'])
405
	{
406 View Code Duplication
		if ($modSettings['postmod_active'] && in_array('post_unapproved_replies_any', $pbe['user_info']['permissions']) && (!in_array('post_reply_any', $pbe['user_info']['permissions'])))
407
			$becomesApproved = false;
408
		elseif (!in_array('post_reply_own', $pbe['user_info']['permissions']))
409
			return pbe_emailError('error_cant_reply', $email_message);
410
	}
411
	elseif (!$pbe['user_info']['is_admin'])
412
	{
413 View Code Duplication
		if ($modSettings['postmod_active'] && in_array('post_unapproved_replies_any', $pbe['user_info']['permissions']) && (!in_array('post_reply_any', $pbe['user_info']['permissions'])))
414
			$becomesApproved = false;
415
		elseif (!in_array('post_reply_any', $pbe['user_info']['permissions']))
416
			return pbe_emailError('error_cant_reply', $email_message);
417
	}
418
419
	// Convert to BBC and Format the message
420
	$html = $email_message->html_found;
421
	$text = pbe_load_text($html, $email_message, $pbe);
422
	if (empty($text))
423
		return pbe_emailError('error_no_message', $email_message);
424
425
	// Seriously? Attachments?
426 View Code Duplication
	if (!empty($email_message->attachments) && !empty($modSettings['maillist_allow_attachments']) && !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1)
427
	{
428
		if (($modSettings['postmod_active'] && in_array('post_unapproved_attachments', $pbe['user_info']['permissions'])) || in_array('post_attachment', $pbe['user_info']['permissions']))
429
			$attachIDs = pbe_email_attachments($pbe, $email_message);
430
		else
431
			$text .= "\n\n" . $txt['error_no_attach'] . "\n";
432
	}
433
434
	// Setup the post variables.
435
	$msgOptions = array(
436
		'id' => 0,
437
		'subject' => strpos($topic_info['subject'], trim($pbe['response_prefix'])) === 0 ? $topic_info['subject'] : $pbe['response_prefix'] . $topic_info['subject'],
438
		'smileys_enabled' => true,
439
		'body' => $text,
440
		'attachments' => empty($attachIDs) ? array() : $attachIDs,
441
		'approved' => $becomesApproved
442
	);
443
444
	$topicOptions = array(
445
		'id' => $topic_info['id_topic'],
446
		'board' => $topic_info['id_board'],
447
		'mark_as_read' => true,
448
		'is_approved' => !$modSettings['postmod_active'] || empty($topic_info['id_topic']) || !empty($topic_info['approved'])
449
	);
450
451
	$posterOptions = array(
452
		'id' => $pbe['profile']['id_member'],
453
		'name' => $pbe['profile']['real_name'],
454
		'email' => $pbe['profile']['email_address'],
455
		'update_post_count' => empty($topic_info['count_posts']),
456
		'ip' => $email_message->load_ip() ? $email_message->ip : $pbe['profile']['member_ip']
457
	);
458
459
	// Make the post.
460
	createPost($msgOptions, $topicOptions, $posterOptions);
461
462
	// We need the auto_notify setting, it may be theme based so pass the theme in use
463
	$theme_settings = query_get_theme($pbe['profile']['id_member'], $pbe['profile']['id_theme'], $topic_info);
464
	$auto_notify = isset($theme_settings['auto_notify']) ? $theme_settings['auto_notify'] : 0;
465
466
	// Turn notifications on or off
467
	query_notifications($pbe['profile']['id_member'], $topic_info['id_board'], $topic_info['id_topic'], $auto_notify, $pbe['user_info']['permissions']);
468
469
	// Notify members who have notification turned on for this,
470
	// but only if it's going to be approved
471
	if ($becomesApproved)
472
	{
473
		require_once(SUBSDIR . '/Notification.subs.php');
474
		sendNotifications($topic_info['id_topic'], 'reply', array(), array(), $pbe);
475
	}
476
477
	return true;
478
}
479
480
/**
481
 * Attempts to create a PM (reply) on the forum
482
 *
483
 * What it does
484
 * - Checks if the user has permissions
485
 * - Calls pbe_load_text to prepare text for the pm
486
 * - Calls query_mark_pms to mark things as read
487
 * - Returns true if successful or false for any number of failures
488
 *
489
 * @uses sendpm to do the actual "sending"
490
 * @package Maillist
491
 * @param mixed[] $pbe array of pbe 'user_info' values
492
 * @param Email_Parse $email_message
493
 * @param mixed[] $pm_info
494
 */
495
function pbe_create_pm($pbe, $email_message, $pm_info)
496
{
497
	global $modSettings, $txt;
498
499
	// Can they send?
500 View Code Duplication
	if (!$pbe['user_info']['is_admin'] && !in_array('pm_send', $pbe['user_info']['permissions']))
501
		return pbe_emailError('error_pm_not_allowed', $email_message);
502
503
	// Convert the PM to BBC and Format the message
504
	$html = $email_message->html_found;
505
	$text = pbe_load_text($html, $email_message, $pbe);
506
	if (empty($text))
507
		return pbe_emailError('error_no_message', $email_message);
508
509
	// If they tried to attach a file, just say sorry
510
	if (!empty($email_message->attachments) && !empty($modSettings['maillist_allow_attachments']) && !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1)
511
		$text .= "\n\n" . $txt['error_no_pm_attach'] . "\n";
512
513
	// For sending the message...
514
	$from = array(
515
		'id' => $pbe['profile']['id_member'],
516
		'name' => $pbe['profile']['real_name'],
517
		'username' => $pbe['profile']['member_name']
518
	);
519
520
	$pm_info['subject'] = strpos($pm_info['subject'], trim($pbe['response_prefix'])) === 0 ? $pm_info['subject'] : $pbe['response_prefix'] . $pm_info['subject'];
521
522
	// send/save the actual PM.
523
	require_once(SUBSDIR . '/PersonalMessage.subs.php');
524
	$pm_result = sendpm(array('to' => array($pm_info['id_member_from']), 'bcc' => array()), $pm_info['subject'], $text, true, $from, $pm_info['id_pm_head']);
525
526
	// Assuming all went well, mark this as read, replied to and update the unread counter
527
	if (!empty($pm_result))
528
		query_mark_pms($email_message, $pbe);
529
530
	return !empty($pm_result);
531
}
532
533
/**
534
 * Create a new topic by email
535
 *
536
 * What it does:
537
 * - Called by pbe_topic to create a new topic or by pbe_main to create a new topic via a subject change
538
 * - checks posting permissions, but requires all email validation checks are complete
539
 * - Calls pbe_load_text to prepare text for the post
540
 * - Calls sendNotifications to announce the new post
541
 * - Calls query_update_member_stats to show they did something
542
 * - Requires the pbe, email_message and board_info arrays to be populated.
543
 *
544
 * @uses createPost to do the actual "posting"
545
 * @package Maillist
546
 * @param mixed[] $pbe array of pbe 'user_info' values
547
 * @param Email_Parse $email_message
548
 * @param mixed[] $board_info
549
 */
550
function pbe_create_topic($pbe, $email_message, $board_info)
551
{
552
	global $txt, $modSettings;
553
554
	// It does not work like that
555
	if (empty($pbe) || empty($email_message))
556
		return false;
557
558
	// We have the board info, and their permissions - do they have a right to start a new topic?
559
	$becomesApproved = true;
560
	if (!$pbe['user_info']['is_admin'])
561
	{
562
		if (!in_array('postby_email', $pbe['user_info']['permissions']))
563
			return pbe_emailError('error_permission', $email_message);
564
		elseif ($modSettings['postmod_active'] && in_array('post_unapproved_topics', $pbe['user_info']['permissions']) && (!in_array('post_new', $pbe['user_info']['permissions'])))
565
			$becomesApproved = false;
566
		elseif (!in_array('post_new', $pbe['user_info']['permissions']))
567
			return pbe_emailError('error_cant_start', $email_message);
568
	}
569
570
	// Approving all new topics by email anyway, smart admin this one is ;)
571
	if (!empty($modSettings['maillist_newtopic_needsapproval']))
572
		$becomesApproved = false;
573
574
	// First on the agenda the subject
575
	$subject = pbe_clean_email_subject($email_message->subject);
576
	$subject = strtr(Util::htmlspecialchars($subject), array("\r" => '', "\n" => '', "\t" => ''));
0 ignored issues
show
Bug introduced by
It seems like $subject can also be of type boolean; however, Util::htmlspecialchars() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
577
578
	// Not to long not to short
579
	if (Util::strlen($subject) > 100)
580
		$subject = Util::substr($subject, 0, 100);
581
	elseif ($subject == '')
582
		return pbe_emailError('error_no_subject', $email_message);
583
584
	// The message itself will need a bit of work
585
	$html = $email_message->html_found;
586
	$text = pbe_load_text($html, $email_message, $pbe);
587
	if (empty($text))
588
		return pbe_emailError('error_no_message', $email_message);
589
590
	// Build the attachment array if needed
591 View Code Duplication
	if (!empty($email_message->attachments) && !empty($modSettings['maillist_allow_attachments']) && !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1)
592
	{
593
		if (($modSettings['postmod_active'] && in_array('post_unapproved_attachments', $pbe['user_info']['permissions'])) || in_array('post_attachment', $pbe['user_info']['permissions']))
594
			$attachIDs = pbe_email_attachments($pbe, $email_message);
595
		else
596
			$text .= "\n\n" . $txt['error_no_attach'] . "\n";
597
	}
598
599
	// If we get to this point ... then its time to play, lets start a topic !
600
	require_once(SUBSDIR . '/Post.subs.php');
601
602
	// Setup the topic variables.
603
	$msgOptions = array(
604
		'id' => 0,
605
		'subject' => $subject,
606
		'smileys_enabled' => true,
607
		'body' => $text,
608
		'attachments' => empty($attachIDs) ? array() : $attachIDs,
609
		'approved' => $becomesApproved
610
	);
611
612
	$topicOptions = array(
613
		'id' => 0,
614
		'board' => $board_info['id_board'],
615
		'mark_as_read' => false
616
	);
617
618
	$posterOptions = array(
619
		'id' => $pbe['profile']['id_member'],
620
		'name' => $pbe['profile']['real_name'],
621
		'email' => $pbe['profile']['email_address'],
622
		'update_post_count' => empty($board_info['count_posts']),
623
		'ip' => (isset($email_message->ip)) ? $email_message->ip : $pbe['profile']['member_ip']
624
	);
625
626
	// Attempt to make the new topic.
627
	createPost($msgOptions, $topicOptions, $posterOptions);
628
629
	// The auto_notify setting
630
	$theme_settings = query_get_theme($pbe['profile']['id_member'], $pbe['profile']['id_theme'], $board_info);
631
	$auto_notify = isset($theme_settings['auto_notify']) ? $theme_settings['auto_notify'] : 0;
632
633
	// Notifications on or off
634
	query_notifications($pbe['profile']['id_member'], $board_info['id_board'], $topicOptions['id'], $auto_notify, $pbe['user_info']['permissions']);
635
636
	// Notify members who have notification turned on for this, (if it's approved)
637
	if ($becomesApproved)
638
	{
639
		require_once(SUBSDIR . '/Notification.subs.php');
640
		sendNotifications($topicOptions['id'], 'reply', array(), array(), $pbe);
641
	}
642
643
	// Update this users info so the log shows them as active
644
	query_update_member_stats($pbe, $email_message, $topicOptions);
645
646
	return true;
647
}
648
649
/**
650
 * Calls the necessary functions to extract and format the message so its ready for posting
651
 *
652
 * What it does:
653
 * - Converts an email response (text or html) to a BBC equivalent via pbe_Email_to_bbc
654
 * - Formats the email response so it looks structured and not chopped up (via pbe_fix_email_body)
655
 *
656
 * @package Maillist
657
 * @param boolean $html
658
 * @param Email_Parse $email_message
659
 * @param mixed[] $pbe
660
 */
661
function pbe_load_text(&$html, $email_message, $pbe)
662
{
663
	if (!$html || ($html && preg_match_all('~<table.*?>~i', $email_message->body, $match) >= 2))
664
	{
665
		// Some mobile responses wrap everything in a table structure so use plain text
666
		$text = $email_message->plain_body;
667
		$html = false;
668
	}
669
	else
670
		$text = un_htmlspecialchars($email_message->body);
671
672
	// Run filters now, before the data is manipulated
673
	$text = pbe_filter_email_message($text);
674
675
	// Convert to BBC and format it so it looks like a post
676
	$text = pbe_email_to_bbc($text, $html);
677
678
	$pbe['profile']['real_name'] = isset($pbe['profile']['real_name']) ? $pbe['profile']['real_name'] : '';
679
	$text = pbe_fix_email_body($text, $html, $pbe['profile']['real_name'], (empty($email_message->_converted_utf8) ? $email_message->headers['x-parameters']['content-type']['charset'] : 'UTF-8'));
680
681
	// Do we even have a message left to post?
682
	$text = Util::htmltrim($text);
683
	if (empty($text))
684
		return;
685
686
	if ($email_message->message_type !== 'p')
687
	{
688
		// Prepare it for the database
689
		require_once(SUBSDIR . '/Post.subs.php');
690
		preparsecode($text);
691
	}
692
693
	return $text;
694
}