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 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 |
|
|
|
|
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" => '')); |
|
|
|
|
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
|
|
|
} |
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.