Completed
Pull Request — patch_1-1-4 (#3210)
by Emanuele
12:56
created

Emailpost_Controller   F

Complexity

Total Complexity 61

Size/Duplication

Total Lines 364
Duplicated Lines 14.01 %

Coupling/Cohesion

Components 0
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 51
loc 364
rs 3.52
c 0
b 0
f 0
ccs 0
cts 154
cp 0
wmc 61
lcom 0
cbo 2

4 Methods

Rating   Name   Duplication   Size   Complexity  
A action_index() 0 5 1
F action_pbe_post() 25 162 35
D action_pbe_topic() 26 100 16
B action_pbe_preview() 0 42 9

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Emailpost_Controller often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Emailpost_Controller, and based on these observations, apply Extract Interface, too.

1
<?php
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
11
 *
12
 */
13
14
/**
15
 * Emailpost_Controller class.
16
 * Handles items pertaining to posting or PM an item that was received by email
17
 *
18
 * @package Maillist
19
 */
20
class Emailpost_Controller extends Action_Controller
21
{
22
	/**
23
	 * Default entry point, it forwards to a worker method,
24
	 * if we ever get here.
25
	 * @see Action_Controller::action_index()
26
	 */
27
	public function action_index()
28
	{
29
		// By default we go to preview
30
		$this->action_pbe_preview();
31
	}
32
33
	/**
34
	 * Main email posting controller, reads, parses, checks and posts an email message or PM
35
	 *
36
	 * What it does:
37
	 *
38
	 * - Allows a user to reply to a topic on the board by emailing a reply to a
39
	 * notification message.
40
	 * - It must have the security key in the email or it will be rejected
41
	 * - It must be from the email of a registered user
42
	 * - The key must have been sent to that user
43
	 * - Keys are used once and then discarded
44
	 * - Accessed by email imap cron script, and ManageMaillist.controller.php.
45
	 *
46
	 * @param string|null $data used to supply a full headers+body email
47
	 * @param boolean $force used to override common failure errors
48
	 * @param string|null $key used to supply a lost key
49
	 * @throws Elk_Exception
50
	 */
51
	public function action_pbe_post($data = null, $force = false, $key = null)
52
	{
53
		global $txt, $modSettings, $language, $user_info, $maintenance;
54
55
		// The function is not even on ...
56
		if (empty($modSettings['maillist_enabled']))
57
			return false;
58
59
		// Our mail parser and our main subs
60
		require_once(SUBSDIR . '/Emailpost.subs.php');
61
62
		// Init
63
		loadLanguage('Maillist');
64
		detectServer()->setMemoryLimit('128M');
65
66
		// Load the email parser and get some data to work with
67
		$email_message = new Email_Parse();
68
		$email_message->read_data($data, BOARDDIR);
69
		if (!$email_message->raw_message)
70
			return false;
71
72
		// Ask for an html version (if available) and some needed details
73
		$email_message->read_email(true, $email_message->raw_message);
74
		$email_message->load_address();
75
		$email_message->load_key($key);
76
77
		// Check if it's a DSN, and handle it
78 View Code Duplication
		if ($email_message->_is_dsn)
79
		{
80
			if (!empty($modSettings['pbe_bounce_detect']))
81
			{
82
				pbe_disable_user_notify($email_message);
83
84
				// @todo Notify the user
85
				if (!empty($modSettings['pbe_bounce_record']))
86
				{
87
					// They can record the message anyway, if they so wish
88
					return pbe_emailError('error_bounced', $email_message);
89
				}
90
91
				// If they don't wish, then return false like recording the failure would do
92
				return false;
93
			}
94
			else
95
			{
96
				// When the auto-disable function is not turned on, record the DSN
97
				// In the failed email table for the admins to handle however
98
				return pbe_emailError('error_bounced', $email_message);
99
			}
100
		}
101
102
		// If the feature is on but the post/pm function is not enabled, just log the message.
103
		if (empty($modSettings['pbe_post_enabled']) && empty($modSettings['pbe_pm_enabled']))
104
			return pbe_emailError('error_email_notenabled', $email_message);
105
106
		// Spam I am?
107
		if ($email_message->load_spam() && !$force)
108
			return pbe_emailError('error_found_spam', $email_message);
109
110
		// Load the user from the database based on the sending email address
111
		$email_message->email['from'] = !empty($email_message->email['from']) ? strtolower($email_message->email['from']) : '';
112
		$pbe = query_load_user_info($email_message->email['from']);
113
114
		// Can't find this email in our database, a non-user, a spammer, a looser, a poser or even worse?
115
		if (empty($pbe))
116
			return pbe_emailError('error_not_find_member', $email_message);
117
118
		// Find the message security key, without it we are not going anywhere ever
119
		if (empty($email_message->message_key_id))
120
			return pbe_emailError('error_missing_key', $email_message);
121
122
		require_once(SUBSDIR . '/Emailpost.subs.php');
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
	 *
219
	 * - New topics do not have security keys in them so they are subject to spoofing
220
	 * - It must be from the email of a registered user
221
	 * - It must have been sent to an email ID that has been set to post new topics
222
	 * - Accessed through emailtopic.
223
	 *
224
	 * @param string|null $data used to supply a full body+headers email
225
	 * @throws Elk_Exception
226
	 */
227
	public function action_pbe_topic($data = null)
228
	{
229
		global $modSettings, $user_info, $maintenance;
230
231
		// The function is not even on ...
232
		if (empty($modSettings['maillist_enabled']))
233
			return false;
234
235
		// Our mail parser and our main subs
236
		require_once(SUBSDIR . '/Emailpost.subs.php');
237
238
		// Init
239
		loadLanguage('Maillist');
240
		detectServer()->setMemoryLimit('256M');
241
242
		// Get the data from one of our sources
243
		$email_message = new Email_Parse();
244
		$email_message->read_data($data, BOARDDIR);
245
		if (!$email_message->raw_message)
246
			return false;
247
248
		// Parse the header and some needed details
249
		$email_message->read_email(true, $email_message->raw_message);
250
		$email_message->load_address();
251
252
		// No key for this, so set some blanks for the error function (if needed)
253
		$email_message->message_type = 'x';
254
		$email_message->message_key_id = '';
255
		$email_message->message_key = '';
256
		$email_message->message_id = 0;
257
258
		// Check if it's a DSN
259
		// Hopefully, this will eventually DO something but for now
260
		// we'll just add it with a more specific error reason
261 View Code Duplication
		if ($email_message->_is_dsn)
262
		{
263
			if (!empty($modSettings['pbe_bounce_detect']))
264
			{
265
				pbe_disable_user_notify($email_message);
266
267
				// @todo Notify the user
268
				if (!empty($modSettings['pbe_bounce_record']))
269
				{
270
					// They can record the message anyway, if they so wish
271
					return pbe_emailError('error_bounced', $email_message);
272
				}
273
274
				// If they don't wish, then return false like recording the failure
275
				return false;
276
			}
277
			else
278
			{
279
				// When the auto-disable function is not turned on, record the DSN
280
				// In the failed email table for the admins to handle however
281
				return pbe_emailError('error_bounced', $email_message);
282
			}
283
		}
284
285
		// If the feature is on but the post/pm function is not enabled, just log the message.
286
		if (empty($modSettings['pbe_post_enabled']))
287
			return pbe_emailError('error_email_notenabled', $email_message);
288
289
		// Load the user from the database based on the sending email address
290
		$email_message->email['from'] = !empty($email_message->email['from']) ? strtolower($email_message->email['from']) : '';
291
		$pbe = query_load_user_info($email_message->email['from']);
292
293
		// Can't find this email as one of our users?
294
		if (empty($pbe))
295
			return pbe_emailError('error_not_find_member', $email_message);
296
297
		// Getting hammy with it?
298
		if ($email_message->load_spam())
299
			return pbe_emailError('error_found_spam', $email_message);
300
301
		// The board that this email address corresponds to
302
		$board_number = pbe_find_board_number($email_message);
303
		if (empty($board_number))
304
			return pbe_emailError('error_not_find_board', $email_message);
305
306
		// In maintenance mode so just save it for the moderators to deal with
307 View Code Duplication
		if (!empty($maintenance) && $maintenance !== 2 && !$pbe['user_info']['is_admin'] && !$user_info['is_admin'])
308
			return pbe_emailError('error_in_maintenance_mode', $email_message);
309
310
		// Any additional spam / security checking
311
		call_integration_hook('integrate_mailist_checks_before', array($email_message, $pbe));
312
313
		// To post a NEW topic, we need some board details for where it goes
314
		$board_info = query_load_board_details($board_number, $pbe);
315
		if (empty($board_info))
316
			return pbe_emailError('error_board_gone', $email_message);
317
318
		// Load up this users permissions for that board
319
		query_load_permissions('board', $pbe, $board_info);
320
321
		// Account for any moderation they may be under
322
		pbe_check_moderation($pbe);
323
324
		// Create the topic, send notifications
325
		return pbe_create_topic($pbe, $email_message, $board_info);
326
	}
327
328
	/**
329
	 * Used to preview a failed email from the ACP
330
	 *
331
	 * What it does:
332
	 *
333
	 * - Called from ManageMaillist.controller, which checks topic/message permission for viewing
334
	 * - Calls pbe_load_text to prepare text for the preview
335
	 * - Returns an array of values for use in the template
336
	 *
337
	 * @param string $data raw email string, including headers
338
	 * @return boolean
339
	 * @throws Elk_Exception
340
	 */
341
	public function action_pbe_preview($data = '')
342
	{
343
		global $txt, $modSettings;
344
345
		// Our mail parser and our main subs
346
		require_once(SUBSDIR . '/Emailpost.subs.php');
347
348
		// Init
349
		$pbe = array();
350
		loadLanguage('Maillist');
351
352
		// Load the email parser and get some data to work with
353
		$email_message = new Email_Parse();
354
		$email_message->read_data($data, BOARDDIR);
355
		if (!$email_message->raw_message)
356
			return false;
357
358
		// Ask for an html version (if available) and some needed details
359
		$email_message->read_email(true, $email_message->raw_message);
360
		$html = $email_message->html_found;
361
		$email_message->load_address();
362
		$email_message->load_key();
363
364
		// Convert to BBC and Format for the preview
365
		$text = pbe_load_text($html, $email_message, $pbe);
366
367
		// If there are attachments, just get the count
368
		$attachment_count = 0;
369
		if (!empty($email_message->attachments) && !empty($modSettings['maillist_allow_attachments']) && !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1)
370
		{
371
			if ($email_message->message_type === 'p')
372
				$text .= "\n\n" . $txt['error_no_pm_attach'] . "\n";
373
			else
374
				$attachment_count = count($email_message->attachments);
375
		}
376
377
		if ($attachment_count)
378
			$text .= "\n\n" . sprintf($txt['email_attachments'], $attachment_count);
379
380
		// Return the parsed and formatted body and who it was sent to for the template
381
		return array('body' => $text, 'to' => implode(' & ', $email_message->email['to']) . (!empty($email_message->email['cc']) ? ', ' . implode(' & ', $email_message->email['cc']) : ''));
382
	}
383
}
384
385
/**
386
 * Attempts to create a reply post on the forum
387
 *
388
 * What it does:
389
 *
390
 * - Checks if the user has permissions to post/reply/postby email
391
 * - Calls pbe_load_text to prepare text for the post
392
 * - returns true if successful or false for any number of failures
393
 *
394
 * @package Maillist
395
 * @param mixed[] $pbe array of all pbe user_info values
396
 * @param Email_Parse $email_message
397
 * @param mixed[] $topic_info
398
 * @throws Elk_Exception
399
 */
400
function pbe_create_post($pbe, $email_message, $topic_info)
401
{
402
	global $modSettings, $txt;
403
404
	// Validate they have permission to reply
405
	$becomesApproved = true;
406
	if (!in_array('postby_email', $pbe['user_info']['permissions']) && !$pbe['user_info']['is_admin'])
407
		return pbe_emailError('error_permission', $email_message);
408 View Code Duplication
	elseif ($topic_info['locked'] && !$pbe['user_info']['is_admin'] && !in_array('moderate_forum', $pbe['user_info']['permissions']))
409
		return pbe_emailError('error_locked', $email_message);
410
	elseif ($topic_info['id_member_started'] === $pbe['profile']['id_member'] && !$pbe['user_info']['is_admin'])
411
	{
412 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'])))
413
			$becomesApproved = false;
414
		elseif (!in_array('post_reply_own', $pbe['user_info']['permissions']))
415
			return pbe_emailError('error_cant_reply', $email_message);
416
	}
417
	elseif (!$pbe['user_info']['is_admin'])
418
	{
419 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'])))
420
			$becomesApproved = false;
421
		elseif (!in_array('post_reply_any', $pbe['user_info']['permissions']))
422
			return pbe_emailError('error_cant_reply', $email_message);
423
	}
424
425
	// Convert to BBC and Format the message
426
	$html = $email_message->html_found;
427
	$text = pbe_load_text($html, $email_message, $pbe);
428
	if (empty($text))
429
		return pbe_emailError('error_no_message', $email_message);
430
431
	// Seriously? Attachments?
432 View Code Duplication
	if (!empty($email_message->attachments) && !empty($modSettings['maillist_allow_attachments']) && !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1)
433
	{
434
		if (($modSettings['postmod_active'] && in_array('post_unapproved_attachments', $pbe['user_info']['permissions'])) || in_array('post_attachment', $pbe['user_info']['permissions']))
435
			$attachIDs = pbe_email_attachments($pbe, $email_message);
436
		else
437
			$text .= "\n\n" . $txt['error_no_attach'] . "\n";
438
	}
439
440
	// Setup the post variables.
441
	$msgOptions = array(
442
		'id' => 0,
443
		'subject' => strpos($topic_info['subject'], trim($pbe['response_prefix'])) === 0 ? $topic_info['subject'] : $pbe['response_prefix'] . $topic_info['subject'],
444
		'smileys_enabled' => true,
445
		'body' => $text,
446
		'attachments' => empty($attachIDs) ? array() : $attachIDs,
447
		'approved' => $becomesApproved
448
	);
449
450
	$topicOptions = array(
451
		'id' => $topic_info['id_topic'],
452
		'board' => $topic_info['id_board'],
453
		'mark_as_read' => true,
454
		'is_approved' => !$modSettings['postmod_active'] || empty($topic_info['id_topic']) || !empty($topic_info['approved'])
455
	);
456
457
	$posterOptions = array(
458
		'id' => $pbe['profile']['id_member'],
459
		'name' => $pbe['profile']['real_name'],
460
		'email' => $pbe['profile']['email_address'],
461
		'update_post_count' => empty($topic_info['count_posts']),
462
		'ip' => $email_message->load_ip() ? $email_message->ip : $pbe['profile']['member_ip']
463
	);
464
465
	// Make the post.
466
	createPost($msgOptions, $topicOptions, $posterOptions);
467
468
	// We need the auto_notify setting, it may be theme based so pass the theme in use
469
	$theme_settings = query_get_theme($pbe['profile']['id_member'], $pbe['profile']['id_theme'], $topic_info);
470
	$auto_notify = isset($theme_settings['auto_notify']) ? $theme_settings['auto_notify'] : 0;
471
472
	// Turn notifications on or off
473
	query_notifications($pbe['profile']['id_member'], $topic_info['id_board'], $topic_info['id_topic'], $auto_notify, $pbe['user_info']['permissions']);
474
475
	// Notify members who have notification turned on for this,
476
	// but only if it's going to be approved
477
	if ($becomesApproved)
478
	{
479
		require_once(SUBSDIR . '/Notification.subs.php');
480
		sendNotifications($topic_info['id_topic'], 'reply', array(), array(), $pbe);
481
	}
482
483
	return true;
484
}
485
486
/**
487
 * Attempts to create a PM (reply) on the forum
488
 *
489
 * What it does
490
 * - Checks if the user has permissions
491
 * - Calls pbe_load_text to prepare text for the pm
492
 * - Calls query_mark_pms to mark things as read
493
 * - Returns true if successful or false for any number of failures
494
 *
495
 * @uses sendpm to do the actual "sending"
496
 * @package Maillist
497
 * @param mixed[] $pbe array of pbe 'user_info' values
498
 * @param Email_Parse $email_message
499
 * @param mixed[] $pm_info
500
 * @throws Elk_Exception
501
 */
502
function pbe_create_pm($pbe, $email_message, $pm_info)
503
{
504
	global $modSettings, $txt;
505
506
	// Can they send?
507 View Code Duplication
	if (!$pbe['user_info']['is_admin'] && !in_array('pm_send', $pbe['user_info']['permissions']))
508
		return pbe_emailError('error_pm_not_allowed', $email_message);
509
510
	// Convert the PM to BBC and Format the message
511
	$html = $email_message->html_found;
512
	$text = pbe_load_text($html, $email_message, $pbe);
513
	if (empty($text))
514
		return pbe_emailError('error_no_message', $email_message);
515
516
	// If they tried to attach a file, just say sorry
517
	if (!empty($email_message->attachments) && !empty($modSettings['maillist_allow_attachments']) && !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1)
518
		$text .= "\n\n" . $txt['error_no_pm_attach'] . "\n";
519
520
	// For sending the message...
521
	$from = array(
522
		'id' => $pbe['profile']['id_member'],
523
		'name' => $pbe['profile']['real_name'],
524
		'username' => $pbe['profile']['member_name']
525
	);
526
527
	$pm_info['subject'] = strpos($pm_info['subject'], trim($pbe['response_prefix'])) === 0 ? $pm_info['subject'] : $pbe['response_prefix'] . $pm_info['subject'];
528
529
	// send/save the actual PM.
530
	require_once(SUBSDIR . '/PersonalMessage.subs.php');
531
	$pm_result = sendpm(array('to' => array($pm_info['id_member_from']), 'bcc' => array()), $pm_info['subject'], $text, true, $from, $pm_info['id_pm_head']);
532
533
	// Assuming all went well, mark this as read, replied to and update the unread counter
534
	if (!empty($pm_result))
535
		query_mark_pms($email_message, $pbe);
536
537
	return !empty($pm_result);
538
}
539
540
/**
541
 * Create a new topic by email
542
 *
543
 * What it does:
544
 *
545
 * - Called by pbe_topic to create a new topic or by pbe_main to create a new topic via a subject change
546
 * - checks posting permissions, but requires all email validation checks are complete
547
 * - Calls pbe_load_text to prepare text for the post
548
 * - Calls sendNotifications to announce the new post
549
 * - Calls query_update_member_stats to show they did something
550
 * - Requires the pbe, email_message and board_info arrays to be populated.
551
 *
552
 * @uses createPost to do the actual "posting"
553
 * @package Maillist
554
 * @param mixed[] $pbe array of pbe 'user_info' values
555
 * @param Email_Parse $email_message
556
 * @param mixed[] $board_info
557
 * @throws Elk_Exception
558
 */
559
function pbe_create_topic($pbe, $email_message, $board_info)
560
{
561
	global $txt, $modSettings;
562
563
	// It does not work like that
564
	if (empty($pbe) || empty($email_message))
565
		return false;
566
567
	// We have the board info, and their permissions - do they have a right to start a new topic?
568
	$becomesApproved = true;
569
	if (!$pbe['user_info']['is_admin'])
570
	{
571
		if (!in_array('postby_email', $pbe['user_info']['permissions']))
572
			return pbe_emailError('error_permission', $email_message);
573
		elseif ($modSettings['postmod_active'] && in_array('post_unapproved_topics', $pbe['user_info']['permissions']) && (!in_array('post_new', $pbe['user_info']['permissions'])))
574
			$becomesApproved = false;
575
		elseif (!in_array('post_new', $pbe['user_info']['permissions']))
576
			return pbe_emailError('error_cant_start', $email_message);
577
	}
578
579
	// Approving all new topics by email anyway, smart admin this one is ;)
580
	if (!empty($modSettings['maillist_newtopic_needsapproval']))
581
		$becomesApproved = false;
582
583
	// First on the agenda the subject
584
	$subject = pbe_clean_email_subject($email_message->subject);
585
	$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...
586
587
	// Not to long not to short
588
	if (Util::strlen($subject) > 100)
589
		$subject = Util::substr($subject, 0, 100);
590
	elseif ($subject == '')
591
		return pbe_emailError('error_no_subject', $email_message);
592
593
	// The message itself will need a bit of work
594
	$html = $email_message->html_found;
595
	$text = pbe_load_text($html, $email_message, $pbe);
596
	if (empty($text))
597
		return pbe_emailError('error_no_message', $email_message);
598
599
	// Build the attachment array if needed
600 View Code Duplication
	if (!empty($email_message->attachments) && !empty($modSettings['maillist_allow_attachments']) && !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1)
601
	{
602
		if (($modSettings['postmod_active'] && in_array('post_unapproved_attachments', $pbe['user_info']['permissions'])) || in_array('post_attachment', $pbe['user_info']['permissions']))
603
			$attachIDs = pbe_email_attachments($pbe, $email_message);
604
		else
605
			$text .= "\n\n" . $txt['error_no_attach'] . "\n";
606
	}
607
608
	// If we get to this point ... then its time to play, lets start a topic !
609
	require_once(SUBSDIR . '/Post.subs.php');
610
611
	// Setup the topic variables.
612
	$msgOptions = array(
613
		'id' => 0,
614
		'subject' => $subject,
615
		'smileys_enabled' => true,
616
		'body' => $text,
617
		'attachments' => empty($attachIDs) ? array() : $attachIDs,
618
		'approved' => $becomesApproved
619
	);
620
621
	$topicOptions = array(
622
		'id' => 0,
623
		'board' => $board_info['id_board'],
624
		'mark_as_read' => false
625
	);
626
627
	$posterOptions = array(
628
		'id' => $pbe['profile']['id_member'],
629
		'name' => $pbe['profile']['real_name'],
630
		'email' => $pbe['profile']['email_address'],
631
		'update_post_count' => empty($board_info['count_posts']),
632
		'ip' => (isset($email_message->ip)) ? $email_message->ip : $pbe['profile']['member_ip']
633
	);
634
635
	// Attempt to make the new topic.
636
	createPost($msgOptions, $topicOptions, $posterOptions);
637
638
	// The auto_notify setting
639
	$theme_settings = query_get_theme($pbe['profile']['id_member'], $pbe['profile']['id_theme'], $board_info);
640
	$auto_notify = isset($theme_settings['auto_notify']) ? $theme_settings['auto_notify'] : 0;
641
642
	// Notifications on or off
643
	query_notifications($pbe['profile']['id_member'], $board_info['id_board'], $topicOptions['id'], $auto_notify, $pbe['user_info']['permissions']);
644
645
	// Notify members who have notification turned on for this, (if it's approved)
646
	if ($becomesApproved)
647
	{
648
		require_once(SUBSDIR . '/Notification.subs.php');
649
		sendNotifications($topicOptions['id'], 'reply', array(), array(), $pbe);
650
	}
651
652
	// Update this users info so the log shows them as active
653
	query_update_member_stats($pbe, $email_message, $topicOptions);
654
655
	return true;
656
}
657
658
/**
659
 * Calls the necessary functions to extract and format the message so its ready for posting
660
 *
661
 * What it does:
662
 *
663
 * - Converts an email response (text or html) to a BBC equivalent via pbe_Email_to_bbc
664
 * - Formats the email response so it looks structured and not chopped up (via pbe_fix_email_body)
665
 *
666
 * @package Maillist
667
 * @param boolean $html
668
 * @param Email_Parse $email_message
669
 * @param mixed[] $pbe
670
 */
671
function pbe_load_text(&$html, $email_message, $pbe)
672
{
673 1
	if (!$html || ($html && preg_match_all('~<table.*?>~i', $email_message->body, $match) >= 2))
674 1
	{
675
		// Some mobile responses wrap everything in a table structure so use plain text
676
		$text = $email_message->plain_body;
677
		$html = false;
678
	}
679
	else
680 1
		$text = un_htmlspecialchars($email_message->body);
681
682
	// Run filters now, before the data is manipulated
683 1
	$text = pbe_filter_email_message($text);
684
685
	// Convert to BBC and format it so it looks like a post
686 1
	$text = pbe_email_to_bbc($text, $html);
687
688 1
	$pbe['profile']['real_name'] = isset($pbe['profile']['real_name']) ? $pbe['profile']['real_name'] : '';
689 1
	$text = pbe_fix_email_body($text, $pbe['profile']['real_name'], (empty($email_message->_converted_utf8) ? $email_message->headers['x-parameters']['content-type']['charset'] : 'UTF-8'));
690
691
	// Do we even have a message left to post?
692 1
	$text = Util::htmltrim($text);
693 1
	if (empty($text))
694 1
		return '';
695
696 1
	if ($email_message->message_type !== 'p')
697 1
	{
698
		// Prepare it for the database
699 1
		require_once(SUBSDIR . '/Post.subs.php');
700 1
		preparsecode($text);
701 1
	}
702
703 1
	return $text;
704
}
705