ManageMaillist::action_unapproved_email()   C
last analyzed

Complexity

Conditions 10
Paths 8

Size

Total Lines 208
Code Lines 125

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
eloc 125
dl 0
loc 208
rs 6.1333
c 0
b 0
f 0
cc 10
nc 8
nop 0
ccs 0
cts 54
cp 0
crap 110

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file contains maillist functions that are specifically done by administrators
5
 * and those with approve email permission
6
 *
7
 * @package   ElkArte Forum
8
 * @copyright ElkArte Forum contributors
9
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
10
 *
11
 * @version 2.0 dev
12
 *
13
 */
14
15
namespace ElkArte\AdminController;
16
17
use BBC\ParserWrapper;
18
use ElkArte\AbstractController;
19
use ElkArte\Action;
20
use ElkArte\Cache\Cache;
21
use ElkArte\Converters\Html2Md;
22
use ElkArte\EventManager;
23
use ElkArte\Exceptions\Exception;
24
use ElkArte\Helper\DataValidator;
25
use ElkArte\Helper\Util;
26
use ElkArte\Languages\Txt;
27
use ElkArte\Maillist\MaillistPost;
28
use ElkArte\Maillist\MaillistPreview;
29
use ElkArte\SettingsForm\SettingsForm;
30
use ElkArte\User;
31
32
/**
33
 * This class is the administration maillist controller.
34
 *
35
 *  - Handles maillist configuration
36
 *  - Handles the showing, repairing, deleting and bouncing failed emails
37
 *  - Handles the adding / editing / removing of both filters and parsers
38
 *
39
 * @package Maillist
40
 */
41
class ManageMaillist extends AbstractController
42
{
43
	/**
44
	 * Main dispatcher.
45
	 *
46
	 * This function checks permissions and passes control to the sub action.
47
	 *
48
	 * @event integrate_sa_manage_maillist Used to add more sub actions
49
	 * @see AbstractController::action_index()
50
	 * @uses Maillist template
51
	 */
52
	public function action_index()
53
	{
54
		global $context, $txt;
55
56
		// Template & language
57
		theme()->getTemplates()->load('Maillist');
58
		Txt::load('Maillist');
59
60
		// All the functions available
61
		$subActions = array(
62
			'emaillist' => array($this, 'action_unapproved_email', 'permission' => 'approve_emails'),
63
			'approve' => array($this, 'action_approve_email', 'permission' => 'approve_emails'),
64
			'delete' => array($this, 'action_delete_email', 'permission' => 'approve_emails'),
65
			'bounce' => array($this, 'action_bounce_email', 'permission' => 'approve_emails'),
66
			'emailtemplates' => array($this, 'action_view_bounce_templates', 'permission' => 'approve_emails'),
67
			'view' => array($this, 'action_view_email', 'permission' => 'approve_emails'),
68
			'emailsettings' => array($this, 'action_settings', 'permission' => 'admin_forum'),
69
			'emailfilters' => array($this, 'action_list_filters', 'permission' => 'admin_forum'),
70
			'editfilter' => array($this, 'action_edit_filters', 'permission' => 'admin_forum'),
71
			'deletefilter' => array($this, 'action_delete_filters', 'permission' => 'admin_forum'),
72
			'emailparser' => array($this, 'action_list_parsers', 'permission' => 'admin_forum'),
73
			'editparser' => array($this, 'action_edit_parsers', 'permission' => 'admin_forum'),
74
			'deleteparser' => array($this, 'action_delete_parsers', 'permission' => 'admin_forum'),
75
			'sortparsers' => array($this, 'action_sort_parsers', 'permission' => 'admin_forum'),
76
			'sortfilters' => array($this, 'action_sort_filters', 'permission' => 'admin_forum'),
77
		);
78
79
		// Action Controller
80
		$action = new Action('manage_maillist');
81
82
		// Help is needed in most places, so load it up front
83
		require_once(SUBSDIR . '/Maillist.subs.php');
84
85
		// Default to sub action 'emaillist' if none was given, call integrate_sa_manage_maillist
86
		$subAction = $action->initialize($subActions, 'emaillist');
87
88
		// Final bits
89
		$context['page_title'] = $txt['ml_admin_configuration'];
90
		$context['sub_action'] = $subAction;
91
92
		// Create the tab area for the template.
93
		$context[$context['admin_menu_name']]['object']->prepareTabData([
94
			'title' => 'ml_admin_configuration',
95
			'help' => 'maillist_help_short',
96
			'description' => 'ml_configuration_desc',
97
			'tabs' => [
98
				'emailfilters' => [
99
					'description' => $txt['filters_title'],
100
				],
101
				'emailparser' => [
102
					'description' => $txt['parsers_title'],
103
				],
104
			]
105
		]);
106
107
		// If you have the permissions, then go Play
108
		$action->dispatch($subAction);
109
	}
110
111
	/**
112
	 * Main listing of failed emails.
113
	 *
114
	 * What it does
115
	 *
116
	 * - Shows the sender, key and subject of the email
117
	 * - Will show the found key if it was missing or possible sender if it was wrong
118
	 * - Icons/Actions to view, bounce, delete or approve a failure
119
	 * - Accessed by ?action=admin;area=maillist;sa=emaillist
120
	 *
121
	 * @event integrate_list_view_email_errors
122
	 * @uses showlist sub template
123
	 */
124
	public function action_unapproved_email()
125
	{
126
		global $context, $modSettings, $txt;
127
128
		// Set an id if none was supplied
129
		$id = $this->_req->getQuery('e_id', 'intval', 0);
130
		if (empty($id) || $id <= 0)
131
		{
132
			$id = 0;
133
		}
134
135
		createToken('admin-ml', 'get');
136
137
		// Build the list option array to display the email data
138
		$listOptions = array(
139
			'id' => 'view_email_errors',
140
			'title' => $txt['ml_emailerror'],
141
			'items_per_page' => $modSettings['defaultMaxMessages'],
142
			'no_items_label' => $txt['ml_emailerror_none'],
143
			'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist']),
144
			'default_sort_col' => 'id_email',
145
			'get_items' => array(
146
				'function' => fn(int $start, int $items_per_page, string $sort = '', int $id = 0): array => $this->list_maillist_unapproved($start, $items_per_page, $sort, $id),
147
				'params' => array(
148
					$id,
149
				),
150
			),
151
			'get_count' => array(
152
				'function' => 'list_maillist_count_unapproved',
153
			),
154
			'columns' => array(
155
				'id_email' => array(
156
					'header' => array(
157
						'value' => $txt['id'],
158
						'class' => 'nowrap',
159
					),
160
					'data' => array(
161
						'db' => 'id_email',
162
					),
163
					'sort' => array(
164
						'default' => 'id_email ',
165
						'reverse' => 'id_email DESC',
166
					),
167
				),
168
				'error' => array(
169
					'header' => array(
170
						'value' => $txt['error'],
171
					),
172
					'data' => array(
173
						'function' => static function ($rowData) {
174
							$error = $rowData['error_code'];
175
							if ($error === 'error_pm_not_found')
176
							{
177
								return '<span class="error">' . $rowData['error'] . '<span>';
178
							}
179
180
							return $rowData['error'];
181
						},
182
					),
183
					'sort' => array(
184
						'default' => 'error ',
185
						'reverse' => 'error DESC',
186
					),
187
				),
188
				'subject' => array(
189
					'header' => array(
190
						'value' => $txt['subject'],
191
					),
192
					'data' => array(
193
						'db' => 'subject',
194
					),
195
					'sort' => array(
196
						'default' => 'subject',
197
						'reverse' => 'subject DESC',
198
					),
199
				),
200
				'key' => array(
201
					'header' => array(
202
						'value' => $txt['key'],
203
					),
204
					'data' => array(
205
						'db' => 'key',
206
						'class' => 'wordbreak'
207
					),
208
					'sort' => array(
209
						'default' => 'message_key',
210
						'reverse' => 'message_key DESC',
211
					),
212
				),
213
				'message' => array(
214
					'header' => array(
215
						'value' => $txt['message_id'],
216
					),
217
					'data' => array(
218
						'sprintf' => array(
219
							'format' => '<a href="%1$s">%2$s</a>',
220
							'params' => array(
221
								'link' => true,
222
								'message' => true,
223
							),
224
						),
225
					),
226
					'sort' => array(
227
						'default' => 'message_id',
228
						'reverse' => 'message_id DESC',
229
					),
230
				),
231
				'from' => array(
232
					'header' => array(
233
						'value' => $txt['from'],
234
					),
235
					'data' => array(
236
						'db' => 'from',
237
					),
238
					'sort' => array(
239
						'default' => 'email_from',
240
						'reverse' => 'email_from DESC',
241
					),
242
				),
243
				'type' => array(
244
					'header' => array(
245
						'value' => $txt['message_type'],
246
					),
247
					'data' => array(
248
						'function' => static function ($rowData) {
249
							global $txt;
250
251
							// Do we have a type?
252
							if (empty($rowData['type']))
253
							{
254
								return $txt['not_applicable'];
255
							}
256
257
							// Personal?
258
							if ($rowData['type'] === 'p')
259
							{
260
								return $txt['personal_message'];
261
							}
262
263
							// New Topic?
264
							if ($rowData['type'] === 'x')
265
							{
266
								return $txt['new_topic'];
267
							}
268
269
							return $txt['topic'] . ' ' . $txt['reply'];
270
						},
271
					),
272
					'sort' => array(
273
						'default' => 'message_type',
274
						'reverse' => 'message_type DESC',
275
					),
276
				),
277
				'action' => array(
278
					'header' => array(
279
						'value' => $txt['message_action'],
280
					),
281
					'data' => array(
282
						'function' => static function ($rowData) {
283
							global $context, $txt;
284
285
							$id = $rowData['id_email'] . ';';
286
							$commands = array();
287
							$security = $context['session_var'] . '=' . $context['session_id'] . ';' . $context['admin-ml_token_var'] . '=' . $context['admin-ml_token'];
288
289
							if ($rowData['error_code'] === 'error_pm_not_found')
290
							{
291
								$commands[] = '<a href="?action=admin;area=maillist;sa=approve;item=' . $id . $security . '" onclick="return confirm(' . JavaScriptEscape($txt['pm_approve_warning']) . ') && submitThisOnce(this);"><i class="icon i-check" title="' . $txt['approve'] . '"></i></a>&nbsp;';
292
							}
293
							else
294
							{
295
								$commands[] = '<a href="?action=admin;area=maillist;sa=approve;item=' . $id . $security . '"><i class="icon i-check" title="' . $txt['approve'] . '"></i></a>&nbsp;';
296
							}
297
298
							$commands[] = '<a href="?action=admin;area=maillist;sa=delete;item=' . $id . $security . '" onclick="return confirm(' . JavaScriptEscape($txt['delete_warning']) . ') && submitThisOnce(this);" accesskey="d"><i class="icon i-delete" title="' . $txt['delete'] . '"></i></a><br />';
299
							$commands[] = '<a href="?action=admin;area=maillist;sa=bounce;item=' . $id . $security . '"><i class="icon i-sign-out" title="' . $txt['bounce'] . '"></i></a>&nbsp;';
300
							$commands[] = '<a href="?action=admin;area=maillist;sa=view;item=' . $id . $security . '"><i class="icon i-view" title="' . $txt['view'] . '"></i></a>';
301
302
							return implode('', $commands);
303
						},
304
					),
305
					'class' => 'listaction',
306
				),
307
			),
308
			'form' => array(
309
				'href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'emaillist']),
310
				'include_sort' => true,
311
				'include_start' => true,
312
			),
313
			'additional_rows' => array(
314
				array(
315
					'position' => 'after_title',
316
					'class' => isset($_SESSION['email_error'], $_SESSION['email_error_type']) ? 'successbox' : (isset($_SESSION['email_error']) ? 'errorbox' : 'description'),
317
					'value' => $this->_req->session->email_error ?? $txt['heading'],
318
				),
319
			),
320
		);
321
322
		// Clear any errors
323
		unset($_SESSION['email_error'], $_SESSION['email_error_type']);
324
325
		// Set the context values for the template
326
		$context['page_title'] = $txt['emailerror_title'];
327
		$context['sub_template'] = 'show_list';
328
		$context['default_list'] = 'view_email_errors';
329
330
		// Create the list.
331
		createList($listOptions);
332
	}
333
334
	/**
335
	 * Show a failed email for review by the moderation team
336
	 *
337
	 * What it does:
338
	 *
339
	 * - Will not show a PM if it has been identified as such
340
	 * - Accessed by ?action=admin;area=maillist;sa=view;item=?
341
	 *
342
	 * @uses show_email sub template
343
	 */
344
	public function action_view_email()
345
	{
346
		global $txt, $context;
347
348
		checkSession('get');
349
		validateToken('admin-ml', 'get');
350
351
		$id = $this->_req->getQuery('item', 'intval', null);
352
		if (!empty($id))
353
		{
354
			// Load up the email details, no funny biz ;)
355
			$temp_email = list_maillist_unapproved($id);
356
357
			if (!empty($temp_email))
358
			{
359
				if ($temp_email[0]['type'] !== 'p' && allowedTo('approve_emails'))
360
				{
361
					// The raw email that failed
362
					$data = $temp_email[0]['body'];
363
364
					// Read/parse this message for viewing
365
					$controller = new MaillistPreview(new EventManager());
366
					$controller->setUser(User::$info);
367
					$result = $controller->action_pbe_preview($data);
368
					$text = $result['body'] ?? '';
369
					$email_to = $result['to'] ?? '';
370
				}
371
				else
372
				{
373
					// PM's mean just that ...
374
					$text = $txt['noaccess'];
375
					$email_to = $txt['private'];
376
				}
377
			}
378
			else
379
			{
380
				$text = $txt['badid'];
381
			}
382
		}
383
		else
384
		{
385
			$text = $txt['badid'];
386
		}
387
388
		$parser = ParserWrapper::instance();
389
390
		// Prep and show the template with what we found
391
		$context['body'] = $parser->parseEmail($text);
392
		$context['to'] = $email_to ?? '';
393
		$context['notice_subject'] = $temp_email[0]['subject'] ?? '';
394
		$context['notice_from'] = $temp_email[0]['from'] ?? '';
395
		$context['page_title'] = $txt['show_notice'];
396
		$context['error_code'] = isset($temp_email[0]['error_code'], $txt[$temp_email[0]['error_code']]) ? $txt[$temp_email[0]['error_code']] : '';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $temp_email does not seem to be defined for all execution paths leading up to this point.
Loading history...
397
		$context['sub_template'] = 'show_email';
398
	}
399
400
	/**
401
	 * Deletes an entry from the database
402
	 *
403
	 * What it does:
404
	 *
405
	 * - Flushes the moderator menu to-do numbers so the menu numbers update
406
	 * - Accessed by ?action=admin;area=maillist;sa=delete;item=?'
407
	 * - Redirects to ?action=admin;area=maillist;sa=emaillist
408
	 */
409
	public function action_delete_email()
410
	{
411
		checkSession('get');
412
		validateToken('admin-ml', 'get');
413
414
		$id = $this->_req->getQuery('item', 'intval', null);
415
416
		// Remove this entry
417
		if (!empty($id))
418
		{
419
			maillist_delete_error_entry($id);
420
		}
421
422
		// Flush the cache
423
		Cache::instance()->remove('num_menu_errors');
424
425
		// Back to the failed list we go
426
		redirectexit('action=admin;area=maillist;sa=emaillist');
427
	}
428
429
	/**
430
	 * Attempts to approve and post a failed email
431
	 *
432
	 * What it does:
433
	 *
434
	 * - Reviews the data to see if the email error function fixed typical issues like key and wrong id
435
	 * - Submits the fixed email to the main function which will post it or fail it again
436
	 * - If successful will remove the entry from the failed log
437
	 * - Accessed by ?action=admin;area=maillist;sa=approve;item=?'
438
	 * - Redirects to action=admin;area=maillist;sa=emaillist
439
	 */
440
	public function action_approve_email()
441
	{
442
		global $txt;
443
444
		checkSession('get');
445
		validateToken('admin-ml', 'get');
446
447
		// Get the id to approve
448
		$id = $this->_req->getQuery('item', 'intval', null);
449
450
		if (!empty($id) && $id !== -1)
451
		{
452
			// Load up the email data
453
			$temp_email = list_maillist_unapproved($id);
454
			if (!empty($temp_email))
455
			{
456
				// Do we have the needed data to approve this, after all it failed for a reason yes?
457
				if (!empty($temp_email[0]['key']) && (!in_array($temp_email[0]['error_code'], array('error_no_message', 'error_not_find_board', 'error_topic_gone'))))
458
				{
459
					// Set up the details needed to get this posted
460
					$key = $temp_email[0]['key'] . '-' . $temp_email[0]['type'] . $temp_email[0]['message'];
461
					$data = $temp_email[0]['body'];
462
463
					// Unknown from email?  Update the message ONLY if we found an appropriate one during the error checking process
464
					if (in_array($temp_email[0]['error_code'], array('error_not_find_member', 'error_key_sender_match')))
465
					{
466
						// did we actually find a potential correct name, if so we post from the valid member
467
						$check_emails = array_pad(explode('=>', $temp_email[0]['from']), 2, '');
468
469
						if (!empty($check_emails[1]))
470
						{
471
							$data = preg_replace('~(From: )(.*<)?(' . preg_quote(trim($check_emails[0]), '~') . ')(>)?(\n)~i', '$1$2' . trim($check_emails[1]) . '$4$5', $data);
472
						}
473
					}
474
475
					// Let's TRY AGAIN to make a post!
476
					$controller = new MaillistPost(new EventManager());
477
					$controller->setUser(User::$info);
478
					$text = $controller->action_pbe_post($data, true, $key);
479
480
					// Assuming all went well, remove this entry and file since we are done.
481
					if ($text)
482
					{
483
						maillist_delete_error_entry($id);
484
485
						// Flush the menu count cache
486
						Cache::instance()->remove('num_menu_errors');
487
488
						$_SESSION['email_error'] = $txt['approved'];
489
						$_SESSION['email_error_type'] = 1;
490
					}
491
					else
492
					{
493
						$_SESSION['email_error'] = $txt['error_approved'];
494
					}
495
				}
496
				else
497
				{
498
					$_SESSION['email_error'] = $txt['cant_approve'];
499
				}
500
			}
501
			else
502
			{
503
				$_SESSION['email_error'] = $txt['badid'];
504
			}
505
		}
506
		else
507
		{
508
			$_SESSION['email_error'] = $txt['badid'];
509
		}
510
511
		// back to the list we go
512
		redirectexit('action=admin;area=maillist;sa=emaillist');
513
	}
514
515
	/**
516
	 * Allows the admin to choose from predefined and custom templates
517
	 *
518
	 * What it does:
519
	 *
520
	 * - Uses the selected template to send a bounce notification with
521
	 * details as specified by the template
522
	 * - Accessed by ?action=admin;area=maillist;sa=bounce;item=?'
523
	 * - Redirects to action=admin;area=maillist;sa=bounced
524
	 * - Provides {MEMBER}, {SCRIPTURL}, {FORUMNAME}, {REGARDS}, {SUBJECT}, {ERROR},
525
	 * {FORUMNAMESHORT}, {EMAILREGARDS} replaceable values to the template
526
	 *
527
	 * @uses bounce_email sub-template
528
	 */
529
	public function action_bounce_email()
530
	{
531
		global $context, $txt, $modSettings, $scripturl, $mbname;
532
533
		if (isset($this->_req->query->bounce))
534
		{
535
			checkSession('get');
536
			validateToken('admin-ml', 'get');
537
		}
538
539
		require_once(SUBSDIR . '/Mail.subs.php');
540
541
		// We should have been sent an email ID
542
		$id = $this->_req->get('item', 'intval');
543
		if (!empty($id))
544
		{
545
			// Load up the email details, no funny biz yall ;)
546
			$temp_email = list_maillist_unapproved($id);
547
548
			if (!empty($temp_email))
549
			{
550
				// Set the options
551
				$this->_req->post->item = (int) $temp_email[0]['id_email'];
552
				$fullerrortext = $txt[$temp_email[0]['error_code']];
553
554
				// Build the template selection area, first the standard ones
555
				$bounce = array('bounce', 'inform');
556
				foreach ($bounce as $k => $type)
557
				{
558
					$context['bounce_templates'][$k]['body'] = $txt['ml_' . $type . '_body'];
559
					$context['bounce_templates'][$k]['subject'] = $txt['ml_' . $type . '_subject'];
560
					$context['bounce_templates'][$k]['title'] = $txt['ml_' . $type . '_title'];
561
				}
562
563
				// And now any custom ones available for this moderator
564
				$context['bounce_templates'] += array_merge($context['bounce_templates'], maillist_templates('bnctpl', $txt['ml_bounce_template_subject_default']));
565
566
				// Replace all the variables in the templates
567
				foreach ($context['bounce_templates'] as $k => $name)
568
				{
569
					$context['bounce_templates'][$k]['body'] = strtr($name['body'], array(
570
						'{MEMBER}' => un_htmlspecialchars($temp_email[0]['name']),
571
						'{SCRIPTURL}' => $scripturl,
572
						'{FORUMNAME}' => $mbname,
573
						'{REGARDS}' => replaceBasicActionUrl($txt['regards_team']),
574
						'{SUBJECT}' => $temp_email[0]['subject'],
575
						'{ERROR}' => $fullerrortext,
576
						'{FORUMNAMESHORT}' => (empty($modSettings['maillist_sitename']) ? $mbname : $modSettings['maillist_sitename']),
577
						'{EMAILREGARDS}' => (empty($modSettings['maillist_sitename_regards']) ? '' : $modSettings['maillist_sitename_regards']),
578
					));
579
				}
580
			}
581
			else
582
			{
583
				$context['settings_message'] = $txt['badid'];
584
			}
585
		}
586
		else
587
		{
588
			$context['settings_message'] = $txt['badid'];
589
		}
590
591
		// Check if they are sending the notice
592
		if (isset($this->_req->post->bounce, $temp_email))
593
		{
594
			checkSession('post');
595
			validateToken('admin-ml');
596
597
			// They did check the box, how else could they have posted
598
			if (isset($this->_req->post->warn_notify))
599
			{
600
				// let's make sure we have the items to send it
601
				$check_emails = explode('=>', $temp_email[0]['from']);
602
				$to = trim($check_emails[0]);
603
				$subject = trim($this->_req->post->warn_sub);
604
				$body = trim($this->_req->post->warn_body);
605
606
				if ($body === '' || $body === '0' || ($subject === '' || $subject === '0'))
607
				{
608
					$context['settings_message'] = $txt['bad_bounce'];
609
				}
610
				else
611
				{
612
					// Time for someone to get a we're so sorry message!
613
					$mark_down = new Html2Md($body);
614
					$body = $mark_down->get_markdown();
615
					sendmail($to, $subject, $body, null, null, false, 5);
616
					redirectexit('action=admin;area=maillist;bounced');
617
				}
618
			}
619
		}
620
621
		// Prepare and show the template
622
		createToken('admin-ml');
623
		$context['warning_data'] = array('notify' => '', 'notify_subject' => '', 'notify_body' => '');
624
		$context['body'] = isset($fullerrortext) ? ParserWrapper::instance()->parseEmail($fullerrortext) : '';
625
		$context['item'] = $this->_req->post->item ?? '';
626
		$context['notice_to'] = $txt['to'] . ' ' . isset($temp_email[0]['from']) !== '' ? $temp_email[0]['from'] : '';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $temp_email does not seem to be defined for all execution paths leading up to this point.
Loading history...
627
		$context['page_title'] = $txt['bounce_title'];
628
		$context['sub_template'] = 'bounce_email';
629
	}
630
631
	/**
632
	 * List all the filters in the system
633
	 *
634
	 * What it does:
635
	 *
636
	 * - Allows to add/edit or delete filters
637
	 * - Filters are used to alter text in a post, to remove crud that comes with emails
638
	 * - Filters can be defined as regex, the system will check it for valid syntax
639
	 * - Accessed by ?action=admin;area=maillist;sa=emailfilters;
640
	 *
641
	 * @event integrate_list_email_filter
642
	 */
643
	public function action_list_filters()
644
	{
645
		global $context, $txt, $modSettings;
646
647
		$id = 0;
648
649
		// Build the listoption array to display the filters
650
		$listOptions = array(
651
			'id' => 'email_filter',
652
			'title' => $txt['filters'],
653
			'items_per_page' => $modSettings['defaultMaxMessages'],
654
			'no_items_label' => $txt['no_filters'],
655
			'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'emailfilters']),
656
			'default_sort_col' => 'name',
657
			'get_items' => array(
658
				'function' => fn(int $start, int $items_per_page, string $sort, int $id, string $style): array => $this->load_filter_parser($start, $items_per_page, $sort, $id, $style),
659
				'params' => array(
660
					$id,
661
					'filter'
662
				),
663
			),
664
			'get_count' => array(
665
				'function' => fn(int $id, string $style): int => $this->count_filter_parser($id, $style),
666
				'params' => array(
667
					$id,
668
					'filter'
669
				),
670
			),
671
			'columns' => array(
672
				'name' => array(
673
					'header' => array(
674
						'value' => $txt['filter_name'],
675
						'style' => 'white-space: nowrap;'
676
					),
677
					'data' => array(
678
						'db' => 'filter_name',
679
					),
680
					'sort' => array(
681
						'default' => 'filter_name, id_filter',
682
						'reverse' => 'filter_name DESC, id_filter DESC',
683
					),
684
				),
685
				'from' => array(
686
					'header' => array(
687
						'value' => $txt['filter_from'],
688
					),
689
					'data' => array(
690
						'db' => 'filter_from',
691
					),
692
					'sort' => array(
693
						'default' => 'filter_from, id_filter',
694
						'reverse' => 'filter_from DESC, id_filter DESC',
695
					),
696
				),
697
				'to' => array(
698
					'header' => array(
699
						'value' => $txt['filter_to'],
700
						'style' => 'width:10em;',
701
					),
702
					'data' => array(
703
						'db' => 'filter_to',
704
					),
705
					'sort' => array(
706
						'default' => 'filter_to, id_filter',
707
						'reverse' => 'filter_to DESC, id_filter DESC',
708
					),
709
				),
710
				'type' => array(
711
					'header' => array(
712
						'value' => $txt['filter_type'],
713
					),
714
					'data' => array(
715
						'db' => 'filter_type',
716
					),
717
					'sort' => array(
718
						'default' => 'filter_type, id_filter',
719
						'reverse' => 'filter_type DESC, id_filter DESC',
720
					),
721
				),
722
				'action' => array(
723
					'header' => array(
724
						'value' => $txt['message_action'],
725
						'class' => 'centertext',
726
					),
727
					'data' => array(
728
						'sprintf' => array(
729
							'format' => '
730
								<a href="?action=admin;area=maillist;sa=editfilter;f_id=%1$s;' . $context['session_var'] . '=' . $context['session_id'] . '">
731
									<i class="icon i-modify" title="' . $txt['modify'] . '"></i>
732
								</a>
733
								<a href="?action=admin;area=maillist;sa=deletefilter;f_id=%1$s;' . $context['session_var'] . '=' . $context['session_id'] . '" onclick="return confirm(' . JavaScriptEscape($txt['filter_delete_warning']) . ') && submitThisOnce(this);" accesskey="d">
734
									<i class="icon i-delete" title="' . $txt['delete'] . '"></i>
735
								</a>',
736
							'params' => array(
737
								'id_filter' => true,
738
							),
739
						),
740
						'class' => 'centertext',
741
						'style' => 'white-space:nowrap;',
742
					),
743
				),
744
			),
745
			'form' => array(
746
				'href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'editfilter']),
747
				'include_sort' => true,
748
				'include_start' => true,
749
				'hidden_fields' => array(
750
					$context['session_var'] => $context['session_id'],
751
				),
752
			),
753
			'additional_rows' => array(
754
				array(
755
					'position' => 'top_of_list',
756
					'class' => isset($this->_req->query->saved) ? 'successbox' : '',
757
					'value' => isset($this->_req->query->saved) ? $txt['saved'] : '',
758
				),
759
				array(
760
					'position' => 'below_table_data',
761
					'class' => 'submitbutton',
762
					'value' => '
763
						<input type="submit" name="addfilter" value="' . $txt['add_filter'] . '" />
764
						<a class="linkbutton" href="' . getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'sortfilters']) . '">' . $txt['sort_filter'] . '</a>',
765
				),
766
			),
767
		);
768
769
		// Set the context values
770
		$context['page_title'] = $txt['filters'];
771
		$context['sub_template'] = 'show_list';
772
		$context['default_list'] = 'email_filter';
773
774
		// Create the list.
775
		createList($listOptions);
776
	}
777
778
	/**
779
	 * Show a full list of all the filters in the system for drag/drop sorting
780
	 *
781
	 * @event integrate_list_sort_email_fp
782
	 */
783
	public function action_sort_filters()
784
	{
785
		global $context, $txt;
786
787
		$id = 0;
788
		$token = createToken('admin-sort');
789
790
		// build the listoption array to display the data
791
		$listOptions = array(
792
			'id' => 'sort_email_fp',
793
			'title' => $txt['sort_filter'],
794
			'sortable' => true,
795
			'items_per_page' => 0,
796
			'no_items_label' => $txt['no_filters'],
797
			'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'sortfilters']),
798
			'get_items' => array(
799
				'function' => fn(int $start, int $items_per_page, string $sort, int $id, string $style): array => $this->load_filter_parser($start, $items_per_page, $sort, $id, $style),
800
				'params' => array(
801
					$id,
802
					'filter'
803
				),
804
			),
805
			'get_count' => array(
806
				'function' => fn(int $id, string $style): int => $this->count_filter_parser($id, $style),
807
				'params' => array(
808
					$id,
809
					'filter'
810
				),
811
			),
812
			'columns' => array(
813
				'filterorder' => array(
814
					'header' => array(
815
						'value' => '',
816
						'class' => 'hide',
817
					),
818
					'data' => array(
819
						'db' => 'filter_order',
820
						'class' => 'hide',
821
					),
822
				),
823
				'name' => array(
824
					'header' => array(
825
						'value' => $txt['filter_name'],
826
						'style' => 'white-space: nowrap;width: 10em'
827
					),
828
					'data' => array(
829
						'db' => 'filter_name',
830
					),
831
				),
832
				'from' => array(
833
					'header' => array(
834
						'value' => $txt['filter_from'],
835
					),
836
					'data' => array(
837
						'db' => 'filter_from',
838
					),
839
				),
840
				'to' => array(
841
					'header' => array(
842
						'value' => $txt['filter_to'],
843
						'style' => 'width:10em;',
844
					),
845
					'data' => array(
846
						'db' => 'filter_to',
847
					),
848
				),
849
				'type' => array(
850
					'header' => array(
851
						'value' => $txt['filter_type'],
852
					),
853
					'data' => array(
854
						'db' => 'filter_type',
855
					),
856
				),
857
			),
858
			'form' => array(
859
				'href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'sortfilters']),
860
				'hidden_fields' => array(
861
					$context['session_var'] => $context['session_id'],
862
				),
863
			),
864
			'additional_rows' => array(
865
				array(
866
					'position' => 'after_title',
867
					'value' => $txt['filter_sort_description'],
868
				),
869
			),
870
			'javascript' => '
871
				$().elkSortable({
872
					sa: "parserorder",
873
					placeholder: "ui-state-highlight",
874
					containment: "#sort_email_fp",
875
					error: "' . $txt['admin_order_error'] . '",
876
					title: "' . $txt['admin_order_title'] . '",
877
					href: "?action=admin;area=maillist;sa=sortfilters",
878
					token: {token_var: "' . $token['admin-sort_token_var'] . '", token_id: "' . $token['admin-sort_token'] . '"}
879
				});
880
			',
881
		);
882
883
		// Set the context values
884
		$context['page_title'] = $txt['filters'];
885
		$context['sub_template'] = 'show_list';
886
		$context['default_list'] = 'sort_email_fp';
887
888
		// Create the list.
889
		createList($listOptions);
890
	}
891
892
	/**
893
	 * Returns the number of filters or parsers in the system
894
	 *
895
	 * - Callback for createList()
896
	 *
897
	 * @param int $id 0 for all of a certain style
898
	 * @param string $style one of filter or parser
899
	 *
900
	 * @return int
901
	 */
902
	public function count_filter_parser($id, $style)
903
	{
904
		return list_count_filter_parser($id, $style);
905
	}
906
907
	/**
908
	 * Returns the details for the filters or parsers in the system
909
	 *
910
	 * - Callback for createList()
911
	 *
912
	 * @param int $start The item to start with (for pagination purposes)
913
	 * @param int $items_per_page The number of items to show per page
914
	 * @param string $sort A string indicating how to sort the results
915
	 * @param int $id
916
	 * @param string $style
917
	 *
918
	 * @return array
919
	 */
920
	public function load_filter_parser($start, $items_per_page, $sort, $id, $style)
921
	{
922
		return list_get_filter_parser($start, $items_per_page, $sort, $id, $style);
923
	}
924
925
	/**
926
	 * Edit or Add a filter
927
	 *
928
	 * - If regex will check for proper syntax before saving to the database
929
	 *
930
	 * @event integrate_save_filter_settings
931
	 *
932
	 */
933
	public function action_edit_filters()
934
	{
935
		global $context, $txt, $modSettings;
936
937
		// Editing an existing filter?
938
		if (isset($this->_req->query->f_id))
939
		{
940
			// Needs to be an int!
941
			$id = (int) $this->_req->query->f_id;
942
			if ($id <= 0)
943
			{
944
				throw new Exception('error_no_id_filter');
945
			}
946
947
			// Load it up and set it as the current values
948
			$row = maillist_load_filter_parser($id, 'filter');
949
			$modSettings['id_filter'] = $row['id_filter'];
950
			$modSettings['filter_type'] = $row['filter_type'];
951
			$modSettings['filter_to'] = $row['filter_to'];
952
			$modSettings['filter_from'] = $row['filter_from'];
953
			$modSettings['filter_name'] = $row['filter_name'];
954
955
			// Some items for the form
956
			$context['page_title'] = $txt['edit_filter'];
957
			$context['editing'] = true;
958
			$context['settings_message'] = array();
959
		}
960
		else
961
		{
962
			// Setup placeholders for adding a new one instead
963
			$modSettings['filter_type'] = '';
964
			$modSettings['filter_to'] = '';
965
			$modSettings['filter_from'] = '';
966
			$modSettings['filter_name'] = '';
967
968
			$context['page_title'] = $txt['add_filter'];
969
			$context['editing'] = false;
970
			$context['settings_message'] = array();
971
		}
972
973
		// Initialize the form
974
		$settingsForm = new SettingsForm(SettingsForm::DB_ADAPTER);
975
976
		// Initialize it with our settings
977
		$config_vars = $this->_filtersSettings();
978
		$settingsForm->setConfigVars($config_vars);
979
980
		// Saving the new or edited entry?
981
		if (isset($this->_req->query->save))
982
		{
983
			checkSession();
984
985
			call_integration_hook('integrate_save_filter_settings');
986
987
			// Editing an entry?
988
			$editId = isset($this->_req->query->edit) && $this->_req->query->edit !== 'new' ? (int) $this->_req->query->edit : -1;
989
			$editName = isset($this->_req->query->edit) && $this->_req->query->edit !== 'new' ? 'id_filter' : '';
990
991
			// If its regex we do a quick check for validity
992
			if ($this->_req->post->filter_type === 'regex')
993
			{
994
				$valid = @preg_replace($this->_req->post->filter_from, $this->_req->post->filter_to, 'ElkArte') !== null;
995
				if (!$valid)
996
				{
997
					// Seems to be bad ... reload the form, set the message
998
					$context['error_type'] = 'notice';
999
					$context['settings_message'][] = $txt['regex_invalid'];
1000
					$modSettings['filter_type'] = $this->_req->post->filter_type;
1001
					$modSettings['filter_to'] = $this->_req->post->filter_to;
1002
					$modSettings['filter_from'] = $this->_req->post->filter_from;
1003
					$modSettings['filter_name'] = $this->_req->post->filter_name;
1004
				}
1005
			}
1006
1007
			if (empty($this->_req->post->filter_type) || empty($this->_req->post->filter_from))
1008
			{
1009
				$context['error_type'] = 'notice';
1010
				$context['settings_message'][] = $txt['filter_invalid'];
1011
			}
1012
1013
			// if we are good to save, so save it ;)
1014
			if (empty($context['settings_message']))
1015
			{
1016
				// And ... its a filter
1017
				$config_vars[] = array('text', 'filter_style');
1018
				$this->_req->post->filter_style = 'filter';
1019
1020
				MaillistSettings::saveTableSettings($config_vars, 'postby_emails_filters', $this->_req->post, array('id_filter'), $editId, $editName);
1021
				redirectexit('action=admin;area=maillist;sa=emailfilters;saved');
1022
			}
1023
		}
1024
1025
		// Prepare some final context for the template
1026
		$title = empty($this->_req->query->saved) ? ($context['editing'] === true ? 'edit_filter' : 'add_filter') : ('saved_filter');
1027
		$context['post_url'] = getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'editfilter', 'edit' => $context['editing'] ? $modSettings['id_filter'] : 'new', 'save']);
1028
		$context['settings_title'] = $txt[$title];
1029
		$context['breadcrumbs'][] = array(
1030
			'url' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'editfilter']),
1031
			'name' => ($context['editing']) ? $txt['edit_filter'] : $txt['add_filter'],
1032
		);
1033
1034
		// Load and show
1035
		$settingsForm->prepare();
1036
		theme()->getTemplates()->load('Admin');
1037
		loadCSSFile('admin.css');
1038
		$context['sub_template'] = 'show_settings';
1039
	}
1040
1041
	/**
1042
	 * Initialize Mailist settings form.
1043
	 *
1044
	 * @event integrate_modify_maillist_filter_settings Add new settings to the maillist filter area
1045
	 */
1046
	private function _filtersSettings()
1047
	{
1048
		global $txt;
1049
1050
		$config_vars = array(
1051
			array('text', 'filter_name', 25, 'subtext' => $txt['filter_name_desc']),
1052
			array('select', 'filter_type',
1053
				array(
1054
					'standard' => $txt['option_standard'],
1055
					'regex' => $txt['option_regex'],
1056
				),
1057
			),
1058
			array('large_text', 'filter_from', 4, 'subtext' => $txt['filter_from_desc']),
1059
			array('text', 'filter_to', 25, 'subtext' => $txt['filter_to_desc']),
1060
		);
1061
1062
		call_integration_hook('integrate_modify_maillist_filter_settings', array(&$config_vars));
1063
1064
		return $config_vars;
1065
	}
1066
1067
	/**
1068
	 * Return the form settings for use in admin search
1069
	 */
1070
	public function filter_search()
1071
	{
1072
		global $modSettings;
1073
1074
		if (empty($modSettings['maillist_enabled']))
1075
		{
1076
			return ['check', 'filter_name'];
1077
		}
1078
1079
		return $this->_filtersSettings();
1080
	}
1081
1082
	/**
1083
	 * Deletes a filter from the system / database
1084
	 */
1085
	public function action_delete_filters()
1086
	{
1087
		// Removing the filter?
1088
		if (isset($this->_req->query->f_id))
1089
		{
1090
			checkSession('get');
1091
			$id = (int) $this->_req->query->f_id;
1092
1093
			maillist_delete_filter_parser($id);
1094
			redirectexit('action=admin;area=maillist;sa=emailfilters;deleted');
1095
		}
1096
	}
1097
1098
	/**
1099
	 * Show a list of all the parsers in the system
1100
	 *
1101
	 * What it does:
1102
	 *
1103
	 * - Allows to add/edit or delete parsers
1104
	 * - Parsers are used to split a message at a line of text
1105
	 * - Parsers can only be defined as regex, the system will check it for valid syntax
1106
	 * - Accessed by ?action=admin;area=maillist;sa=emailparser;
1107
	 *
1108
	 * @event integrate_list_email_parser
1109
	 */
1110
	public function action_list_parsers()
1111
	{
1112
		global $context, $txt, $modSettings;
1113
1114
		$id = 0;
1115
1116
		// Build the listoption array to display the data
1117
		$listOptions = array(
1118
			'id' => 'email_parser',
1119
			'title' => $txt['parsers'],
1120
			'items_per_page' => $modSettings['defaultMaxMessages'],
1121
			'no_items_label' => $txt['no_parsers'],
1122
			'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'emailparser']),
1123
			'get_items' => array(
1124
				'function' => fn(int $start, int $items_per_page, string $sort, int $id, string $style): array => $this->load_filter_parser($start, $items_per_page, $sort, $id, $style),
1125
				'params' => array(
1126
					$id,
1127
					'parser'
1128
				),
1129
			),
1130
			'get_count' => array(
1131
				'function' => fn(int $id, string $style): int => $this->count_filter_parser($id, $style),
1132
				'params' => array(
1133
					$id,
1134
					'parser'
1135
				),
1136
			),
1137
			'columns' => array(
1138
				'name' => array(
1139
					'header' => array(
1140
						'value' => $txt['parser_name'],
1141
						'style' => 'white-space: nowrap;'
1142
					),
1143
					'data' => array(
1144
						'db' => 'filter_name',
1145
					),
1146
					'sort' => array(
1147
						'default' => 'filter_name',
1148
						'reverse' => 'filter_name DESC',
1149
					),
1150
				),
1151
				'from' => array(
1152
					'header' => array(
1153
						'value' => $txt['parser_from'],
1154
					),
1155
					'data' => array(
1156
						'db' => 'filter_from',
1157
					),
1158
					'sort' => array(
1159
						'default' => 'filter_from',
1160
						'reverse' => 'filter_from DESC',
1161
					),
1162
				),
1163
				'type' => array(
1164
					'header' => array(
1165
						'value' => $txt['parser_type'],
1166
					),
1167
					'data' => array(
1168
						'db' => 'filter_type',
1169
					),
1170
					'sort' => array(
1171
						'default' => 'filter_type',
1172
						'reverse' => 'filter_type DESC',
1173
					),
1174
				),
1175
				'action' => array(
1176
					'header' => array(
1177
						'value' => $txt['message_action'],
1178
						'class' => 'centertext',
1179
					),
1180
					'data' => array(
1181
						'sprintf' => array(
1182
							'format' => '
1183
								<a href="?action=admin;area=maillist;sa=editparser;f_id=%1$s;' . $context['session_var'] . '=' . $context['session_id'] . '">
1184
									<i class="icon i-modify" title="' . $txt['modify'] . '"></i>
1185
								</a>
1186
								<a href="?action=admin;area=maillist;sa=deleteparser;f_id=%1$s;' . $context['session_var'] . '=' . $context['session_id'] . '" onclick="return confirm(' . JavaScriptEscape($txt['parser_delete_warning']) . ') && submitThisOnce(this);" accesskey="d">
1187
									<i class="icon i-delete" title="' . $txt['delete'] . '"></i>
1188
								</a>',
1189
							'params' => array(
1190
								'id_filter' => true,
1191
							),
1192
						),
1193
						'class' => 'centertext',
1194
						'style' => 'white-space:nowrap;',
1195
					),
1196
				),
1197
			),
1198
			'form' => array(
1199
				'href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'editparser']),
1200
				'include_sort' => true,
1201
				'include_start' => true,
1202
				'hidden_fields' => array(
1203
					$context['session_var'] => $context['session_id'],
1204
				),
1205
			),
1206
			'additional_rows' => array(
1207
				array(
1208
					'position' => 'top_of_list',
1209
					'class' => isset($this->_req->query->saved) ? 'successbox' : '',
1210
					'value' => isset($this->_req->query->saved) ? $txt['saved'] : '',
1211
				),
1212
				array(
1213
					'position' => 'below_table_data',
1214
					'class' => 'submitbutton',
1215
					'value' => '
1216
						<input type="submit" name="addparser" value="' . $txt['add_parser'] . '" />
1217
						<a class="linkbutton" href="' . getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'sortparsers']) . '">' . $txt['sort_parser'] . '</a>',
1218
				),
1219
			),
1220
		);
1221
1222
		// Set the context values
1223
		$context['page_title'] = $txt['parsers'];
1224
		$context['sub_template'] = 'show_list';
1225
		$context['default_list'] = 'email_parser';
1226
1227
		// Create the list.
1228
		createList($listOptions);
1229
	}
1230
1231
	/**
1232
	 * Show a full list of all the parsers in the system for drag/drop sorting
1233
	 *
1234
	 * @event integrate_list_email_parser
1235
	 */
1236
	public function action_sort_parsers()
1237
	{
1238
		global $context, $txt;
1239
1240
		$id = 0;
1241
		$token = createToken('admin-sort');
1242
1243
		// Build the listoption array to display the data
1244
		$listOptions = array(
1245
			'id' => 'sort_email_fp',
1246
			'title' => $txt['sort_parser'],
1247
			'sortable' => true,
1248
			'items_per_page' => 0,
1249
			'no_items_label' => $txt['no_parsers'],
1250
			'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'sortparsers']),
1251
			'get_items' => array(
1252
				'function' => fn(int $start, int $items_per_page, string $sort, int $id, string $style): array => $this->load_filter_parser($start, $items_per_page, $sort, $id, $style),
1253
				'params' => array(
1254
					$id,
1255
					'parser'
1256
				),
1257
			),
1258
			'get_count' => array(
1259
				'function' => fn(int $id, string $style): int => $this->count_filter_parser($id, $style),
1260
				'params' => array(
1261
					$id,
1262
					'parser'
1263
				),
1264
			),
1265
			'columns' => array(
1266
				'filterorder' => array(
1267
					'header' => array(
1268
						'value' => '',
1269
						'class' => 'hide',
1270
					),
1271
					'data' => array(
1272
						'db' => 'filter_order',
1273
						'class' => 'hide',
1274
					),
1275
				),
1276
				'name' => array(
1277
					'header' => array(
1278
						'value' => $txt['parser_name'],
1279
						'style' => 'white-space: nowrap;width: 10em'
1280
					),
1281
					'data' => array(
1282
						'db' => 'filter_name',
1283
					),
1284
				),
1285
				'from' => array(
1286
					'header' => array(
1287
						'value' => $txt['parser_from'],
1288
					),
1289
					'data' => array(
1290
						'db' => 'filter_from',
1291
					),
1292
				),
1293
				'type' => array(
1294
					'header' => array(
1295
						'value' => $txt['parser_type'],
1296
					),
1297
					'data' => array(
1298
						'db' => 'filter_type',
1299
					),
1300
				),
1301
			),
1302
			'form' => array(
1303
				'href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'sortparsers']),
1304
				'hidden_fields' => array(
1305
					$context['session_var'] => $context['session_id'],
1306
				),
1307
			),
1308
			'additional_rows' => array(
1309
				array(
1310
					'position' => 'after_title',
1311
					'value' => $txt['parser_sort_description'],
1312
				),
1313
			),
1314
			'javascript' => '
1315
				$().elkSortable({
1316
					sa: "parserorder",
1317
					placeholder: "ui-state-highlight",
1318
					containment: "#sort_email_fp",
1319
					error: "' . $txt['admin_order_error'] . '",
1320
					title: "' . $txt['admin_order_title'] . '",
1321
					href: "?action=admin;;area=maillist;sa=sortparsers",
1322
					token: {token_var: "' . $token['admin-sort_token_var'] . '", token_id: "' . $token['admin-sort_token'] . '"}
1323
				});
1324
			',
1325
		);
1326
1327
		// Set the context values
1328
		$context['page_title'] = $txt['parsers'];
1329
		$context['sub_template'] = 'show_list';
1330
		$context['default_list'] = 'sort_email_fp';
1331
1332
		// Create the list.
1333
		createList($listOptions);
1334
	}
1335
1336
	/**
1337
	 * Adds or Edits an existing parser
1338
	 *
1339
	 * - All parsers are assumed regex
1340
	 *
1341
	 * @event integrate_save_parser_settings
1342
	 */
1343
	public function action_edit_parsers()
1344
	{
1345
		global $context, $txt, $modSettings;
1346
1347
		// Editing an existing filter?
1348
		if (isset($this->_req->query->f_id))
1349
		{
1350
			// Needs to be an int!
1351
			$id = (int) $this->_req->query->f_id;
1352
			if ($id <= 0)
1353
			{
1354
				throw new Exception('error_no_id_filter');
1355
			}
1356
1357
			// Load this filter so we can edit it
1358
			$row = maillist_load_filter_parser($id, 'parser');
1359
1360
			$modSettings['id_filter'] = $row['id_filter'];
1361
			$modSettings['filter_type'] = $row['filter_type'];
1362
			$modSettings['filter_from'] = $row['filter_from'];
1363
			$modSettings['filter_name'] = $row['filter_name'];
1364
1365
			$context['page_title'] = $txt['edit_parser'];
1366
			$context['editing'] = true;
1367
		}
1368
		else
1369
		{
1370
			// Setup placeholders for adding a new one instead
1371
			$modSettings['filter_type'] = '';
1372
			$modSettings['filter_name'] = '';
1373
			$modSettings['filter_from'] = '';
1374
1375
			// To the template we go
1376
			$context['page_title'] = $txt['add_parser'];
1377
			$context['editing'] = false;
1378
		}
1379
1380
		// Initialize the form
1381
		$settingsForm = new SettingsForm(SettingsForm::DB_ADAPTER);
1382
1383
		// Initialize it with our settings
1384
		$config_vars = $this->_parsersSettings();
1385
		$settingsForm->setConfigVars($config_vars);
1386
1387
		// Check if they are saving the changes
1388
		if (isset($this->_req->query->save))
1389
		{
1390
			checkSession();
1391
1392
			call_integration_hook('integrate_save_parser_settings');
1393
1394
			// Editing a parser?
1395
			$editId = isset($this->_req->query->edit) && $this->_req->query->edit !== 'new' ? (int) $this->_req->query->edit : -1;
1396
			$editName = isset($this->_req->query->edit) && $this->_req->query->edit !== 'new' ? 'id_filter' : '';
1397
1398
			// Test the regex
1399
			if ($this->_req->post->filter_type === 'regex' && !empty($this->_req->post->filter_from))
1400
			{
1401
				$valid = preg_replace($this->_req->post->filter_from, '', 'ElkArte') !== null;
1402
				if (!$valid)
1403
				{
1404
					// Regex did not compute .. Danger, Will Robinson
1405
					$context['settings_message'] = $txt['regex_invalid'];
1406
					$context['error_type'] = 'notice';
1407
1408
					$modSettings['filter_type'] = $this->_req->post->filter_type;
1409
					$modSettings['filter_from'] = $this->_req->post->filter_from;
1410
					$modSettings['filter_name'] = $this->_req->post->filter_name;
1411
				}
1412
			}
1413
1414
			if (empty($this->_req->post->filter_type) || empty($this->_req->post->filter_from))
1415
			{
1416
				$context['error_type'] = 'notice';
1417
				$context['settings_message'][] = $txt['filter_invalid'];
1418
			}
1419
1420
			// All clear to save?
1421
			if (empty($context['settings_message']))
1422
			{
1423
				// Shhh ... its really a parser
1424
				$config_vars[] = array('text', 'filter_style');
1425
				$this->_req->post->filter_style = 'parser';
1426
1427
				// Save, log, show
1428
				MaillistSettings::saveTableSettings($config_vars, 'postby_emails_filters', $this->_req->post, array('id_filter'), $editId, $editName);
1429
				redirectexit('action=admin;area=maillist;sa=emailparser;saved');
1430
			}
1431
		}
1432
1433
		// Prepare the context for viewing
1434
		$title = ((isset($this->_req->query->saved) && $this->_req->query->saved == '1') ? 'saved_parser' : ($context['editing'] === true ? 'edit_parser' : 'add_parser'));
1435
		$context['settings_title'] = $txt[$title];
1436
		$context['post_url'] = getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'editparser', 'edit' => $context['editing'] ? $modSettings['id_filter'] : 'new', 'save']);
1437
		$context['breadcrumbs'][] = [
1438
			'url' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'editparser']),
1439
			'name' => ($context['editing']) ? $txt['edit_parser'] : $txt['add_parser'],
1440
		];
1441
1442
		// prep it, load it, show it
1443
		$settingsForm->prepare();
1444
		theme()->getTemplates()->load('Admin');
1445
		loadCSSFile('admin.css');
1446
		$context['sub_template'] = 'show_settings';
1447
	}
1448
1449
	/**
1450
	 * Initialize Mailist settings form.
1451
	 *
1452
	 * @event integrate_modify_maillist_parser_settings Add settings to the maillist parser screen
1453
	 */
1454
	private function _parsersSettings()
1455
	{
1456
		global $txt;
1457
1458
		$config_vars = array(
1459
			array('text', 'filter_name', 25, 'subtext' => $txt['parser_name_desc']),
1460
			array('select', 'filter_type', 'subtext' => $txt['parser_type_desc'],
1461
				array(
1462
					'regex' => $txt['option_regex'],
1463
					'standard' => $txt['option_standard'],
1464
				),
1465
			),
1466
			array('large_text', 'filter_from', 4, 'subtext' => $txt['parser_from_desc']),
1467
		);
1468
1469
		call_integration_hook('integrate_modify_maillist_parser_settings', array(&$config_vars));
1470
1471
		return $config_vars;
1472
	}
1473
1474
	/**
1475
	 * Return the form settings for use in admin search
1476
	 */
1477
	public function parser_search()
1478
	{
1479
		global $modSettings;
1480
1481
		if (empty($modSettings['maillist_enabled']))
1482
		{
1483
			return ['check', 'filter_name'];
1484
		}
1485
1486
		return $this->_parsersSettings();
1487
	}
1488
1489
	/**
1490
	 * Removes a parser from the system and database
1491
	 */
1492
	public function action_delete_parsers()
1493
	{
1494
		// Removing the filter?
1495
		if (isset($this->_req->query->f_id))
1496
		{
1497
			checkSession('get');
1498
			$id = (int) $this->_req->query->f_id;
1499
1500
			maillist_delete_filter_parser($id);
1501
			redirectexit('action=admin;area=maillist;sa=emailparser;deleted');
1502
		}
1503
	}
1504
1505
	/**
1506
	 * All the post by email settings, used to control how the feature works
1507
	 *
1508
	 * @event integrate_save_maillist_settings
1509
	 * @uses Admin language
1510
	 */
1511
	public function action_settings()
1512
	{
1513
		global $context, $txt, $modSettings;
1514
1515
		// Be nice, show them we did something
1516
		if (isset($this->_req->query->saved))
1517
		{
1518
			$context['settings_message'] = $txt['saved'];
1519
		}
1520
1521
		// Templates and language
1522
		Txt::load('Admin');
1523
		theme()->getTemplates()->load('Admin');
1524
		loadCSSFile('admin.css');
1525
1526
		// Load any existing email => board values used for new topic creation
1527
		$context['maillist_from_to_board'] = array();
1528
		$data = (empty($modSettings['maillist_receiving_address'])) ? array() : Util::unserialize($modSettings['maillist_receiving_address']);
1529
		foreach ($data as $key => $addr)
1530
		{
1531
			$context['maillist_from_to_board'][$key] = array(
1532
				'id' => $key,
1533
				'emailfrom' => $addr[0],
1534
				'boardto' => $addr[1],
1535
			);
1536
		}
1537
1538
		// Initialize the maillist settings form
1539
		$settingsForm = new SettingsForm(SettingsForm::DB_ADAPTER);
1540
1541
		// Initialize it with our settings
1542
		$settingsForm->setConfigVars($this->_settings());
1543
1544
		// Saving settings?
1545
		if (isset($this->_req->query->save))
1546
		{
1547
			checkSession();
1548
1549
			call_integration_hook('integrate_save_maillist_settings');
1550
1551
			$email_error = false;
1552
			$board_error = false;
1553
			$maillist_receiving_address = array();
1554
1555
			// Basic checking of the email addresses
1556
			if (!DataValidator::is_valid($this->_req->post, array('maillist_sitename_address' => 'valid_email'), array('maillist_sitename_address' => 'trim')))
1557
			{
1558
				$email_error = $this->_req->post->maillist_sitename_address;
1559
			}
1560
1561
			if (!DataValidator::is_valid($this->_req->post, array('maillist_sitename_help' => 'valid_email'), array('maillist_sitename_help' => 'trim')))
1562
			{
1563
				$email_error = $this->_req->post->maillist_sitename_help;
1564
			}
1565
1566
			if (!DataValidator::is_valid($this->_req->post, array('maillist_mail_from' => 'valid_email'), array('maillist_mail_from' => 'trim')))
1567
			{
1568
				$email_error = $this->_req->post->maillist_mail_from;
1569
			}
1570
1571
			// Inbound email set up then we need to check for both valid email and valid board
1572
			if (!$email_error && !empty($this->_req->post->emailfrom))
1573
			{
1574
				// Get the board ids for a quick check
1575
				$boards = maillist_board_list();
1576
1577
				// Check the receiving emails and the board id as well
1578
				$boardtocheck = empty($this->_req->post->boardto) ? array() : $this->_req->post->boardto;
1579
				$addresstocheck = empty($this->_req->post->emailfrom) ? array() : $this->_req->post->emailfrom;
1580
1581
				foreach ($addresstocheck as $key => $checkme)
1582
				{
1583
					// Valid email syntax
1584
					if (!DataValidator::is_valid($addresstocheck, array($key => 'valid_email'), array($key => 'trim')))
1585
					{
1586
						$email_error = $checkme;
1587
						$context['error_type'] = 'notice';
1588
						continue;
1589
					}
1590
1591
					// Valid board id?
1592
					if (!isset($boardtocheck[$key], $boards[$key]))
1593
					{
1594
						$board_error = $checkme;
1595
						$context['error_type'] = 'notice';
1596
						continue;
1597
					}
1598
1599
					// Decipher as [0] emailaddress and [1] board id
1600
					$maillist_receiving_address[] = array($checkme, $boardtocheck[$key]);
1601
				}
1602
			}
1603
1604
			// Enable or disable the fake cron
1605
			enable_maillist_imap_cron(!empty($this->_req->post->maillist_imap_cron));
1606
1607
			// Check and set any errors or give the go ahead to save
1608
			if ($email_error)
1609
			{
1610
				$context['settings_message'] = sprintf($txt['email_not_valid'], $email_error);
1611
			}
1612
			elseif ($board_error)
1613
			{
1614
				$context['settings_message'] = sprintf($txt['board_not_valid'], $board_error);
1615
			}
1616
			else
1617
			{
1618
				// Clear the moderation count cache
1619
				Cache::instance()->remove('num_menu_errors');
1620
1621
				// Should be off if mail posting is on, we ignore it anyway but this at least updates the ACP
1622
				if (!empty($this->_req->post->maillist_enabled))
1623
				{
1624
					updateSettings(array('disallow_sendBody' => ''));
1625
				}
1626
1627
				updateSettings(array('maillist_receiving_address' => serialize($maillist_receiving_address)));
1628
				$settingsForm->setConfigValues((array) $this->_req->post);
1629
				$settingsForm->save();
1630
				writeLog();
1631
				redirectexit('action=admin;area=maillist;sa=emailsettings;saved');
1632
			}
1633
		}
1634
1635
		// Javascript vars for the "add more" buttons in the receive_email callback
1636 2
		$board_list = maillist_board_list();
1637
		$script = '';
1638 2
		$i = 0;
1639
1640
		// Create the board selection list
1641
		foreach ($board_list as $board_id => $board_name)
1642 2
		{
1643
			$script .= $i++ . ': {id:' . $board_id . ', name:' . JavaScriptEscape($board_name) . '},';
1644
		}
1645
1646 2
		theme()->addInlineJavascript('
1647 2
		var sEmailParent = \'add_more_email_placeholder\',
1648 2
			oEmailOptionsdt = {size: \'50\', name: \'emailfrom[]\', class: \'input_text\'},
1649
			oEmailOptionsdd = {size: \'1\', type: \'select\', name: \'boardto[]\', class: \'input_select\'},
1650
			oEmailSelectData = {' . $script . '};
1651
1652
			document.getElementById(\'add_more_board_div\').style.display = \'block\';', true
1653 2
		);
1654 2
1655 2
		$context['boards'] = $board_list;
1656 2
		$context['settings_title'] = $txt['ml_emailsettings'];
1657 2
		$context['page_title'] = $txt['ml_emailsettings'];
1658
		$context['post_url'] = getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'emailsettings', 'save']);
1659
		$context['sub_template'] = 'show_settings';
1660
		$settingsForm->prepare();
1661 2
	}
1662
1663
	/**
1664
	 * Load up the config var array for settings display etc.
1665 2
	 *
1666 2
	 * @event integrate_modify_maillist_settings
1667 2
	 */
1668 2
	private function _settings()
1669 2
	{
1670
		global $txt;
1671
1672
		// Define the menu
1673 2
		$config_vars = [
1674
			['desc', 'maillist_help'],
1675
			['check', 'maillist_enabled'],
1676
			['check', 'pbe_post_enabled'],
1677
			['check', 'pbe_pm_enabled'],
1678
			['check', 'pbe_no_mod_notices', 'subtext' => $txt['pbe_no_mod_notices_desc'], 'postinput' => $txt['recommended']],
1679
			['check', 'pbe_bounce_detect', 'subtext' => $txt['pbe_bounce_detect_desc'], 'postinput' => $txt['experimental']],
1680
			['check', 'pbe_bounce_record', 'subtext' => $txt['pbe_bounce_record_desc'], 'postinput' => $txt['experimental']],
1681
			['title', 'maillist_outbound'],
1682
			['desc', 'maillist_outbound_desc'],
1683 2
			['check', 'maillist_group_mode'],
1684
			['check', 'maillist_digest_enabled'],
1685 2
			['text', 'maillist_sitename', 40, 'subtext' => $txt['maillist_sitename_desc'], 'postinput' => $txt['maillist_sitename_post']],
1686
			['text', 'maillist_sitename_address', 40, 'subtext' => $txt['maillist_sitename_address_desc'], 'postinput' => $txt['maillist_sitename_address_post']],
1687 2
			['text', 'maillist_mail_from', 40, 'subtext' => $txt['maillist_mail_from_desc'], 'postinput' => $txt['maillist_mail_from_post']],
1688 2
			['text', 'maillist_sitename_help', 40, 'subtext' => $txt['maillist_sitename_help_desc'], 'postinput' => $txt['maillist_sitename_help_post']],
1689 2
			['text', 'maillist_sitename_regards', 40, 'subtext' => $txt['maillist_sitename_regards_desc']],
1690 2
			['title', 'maillist_inbound'],
1691 2
			['desc', 'maillist_inbound_desc'],
1692
			['check', 'maillist_newtopic_change'],
1693 2
			['check', 'maillist_newtopic_needsapproval', 'subtext' => $txt['maillist_newtopic_needsapproval_desc'], 'postinput' => $txt['recommended']],
1694 2
			['callback', 'maillist_receive_email_list'],
1695 2
			['title', 'misc'],
1696 2
			['check', 'maillist_allow_attachments'],
1697 2
			['int', 'maillist_key_active', 4, 'subtext' => $txt['maillist_key_active_desc']],
1698 2
			'',
1699 2
			['text', 'maillist_leftover_remove', 40, 'subtext' => $txt['maillist_leftover_remove_desc']],
1700
			['text', 'maillist_sig_keys', 40, 'subtext' => $txt['maillist_sig_keys_desc']],
1701 2
			['int', 'maillist_short_line', 4, 'subtext' => $txt['maillist_short_line_desc']],
1702 2
		];
1703
1704
		// Imap?
1705
		if (!function_exists('imap_open'))
1706
		{
1707 2
			$config_vars = array_merge($config_vars,
1708
				[
1709 2
					['title', 'maillist_imap_missing'],
1710
				]
1711
			);
1712
		}
1713
		else
1714
		{
1715 2
			$config_vars = array_merge($config_vars, [
1716
				['title', 'maillist_imap'],
1717 2
				['desc', 'maillist_imap_reason'],
1718
				['text', 'maillist_imap_host', 45, 'subtext' => $txt['maillist_imap_host_desc'], 'disabled' => !function_exists('imap_open')],
1719
				['text', 'maillist_imap_mailbox', 20, 'postinput' => $txt['maillist_imap_mailbox_desc'], 'disabled' => !function_exists('imap_open')],
1720
				['text', 'maillist_imap_uid', 20, 'postinput' => $txt['maillist_imap_uid_desc'], 'disabled' => !function_exists('imap_open')],
1721
				['password', 'maillist_imap_pass', 20, 'postinput' => $txt['maillist_imap_pass_desc'], 'disabled' => !function_exists('imap_open')],
1722
				['select', 'maillist_imap_connection',
1723
					[
1724
						'imap' => $txt['maillist_imap_unsecure'],
1725
						'pop3' => $txt['maillist_pop3_unsecure'],
1726
						'imaptls' => $txt['maillist_imap_tls'],
1727
						'imapssl' => $txt['maillist_imap_ssl'],
1728
						'pop3tls' => $txt['maillist_pop3_tls'],
1729
						'pop3ssl' => $txt['maillist_pop3_ssl']
1730
					], 'postinput' => $txt['maillist_imap_connection_desc'], 'disabled' => !function_exists('imap_open'),
1731
				],
1732
				['check', 'maillist_imap_delete', 20, 'subtext' => $txt['maillist_imap_delete_desc'], 'disabled' => !function_exists('imap_open')],
1733
				['check', 'maillist_imap_cron', 20, 'subtext' => $txt['maillist_imap_cron_desc'], 'disabled' => !function_exists('imap_open')],
1734
			]);
1735
		}
1736
1737
		call_integration_hook('integrate_modify_maillist_settings', array(&$config_vars));
1738
1739
		return $config_vars;
1740
	}
1741
1742
	/**
1743
	 * Return the form settings for use in admin search
1744
	 */
1745
	public function settings_search()
1746
	{
1747
		global $modSettings;
1748
1749
		if (empty($modSettings['maillist_enabled']))
1750
		{
1751
			return ['check', 'maillist_enabled'];
1752
		}
1753
1754
		return $this->_settings();
1755
	}
1756
1757
	/**
1758
	 * View all the custom email bounce templates.
1759
	 *
1760
	 * What it does:
1761
	 *
1762
	 * - Shows all the bounce templates in the system available to this user
1763
	 * - Provides for actions to add or delete them
1764
	 * - Accessed by ?action=admin;area=maillist;sa=emailtemplates;
1765
	 *
1766
	 * @event integrate_list_bounce_template_list
1767
	 */
1768
	public function action_view_bounce_templates()
1769
	{
1770
		global $modSettings, $context, $txt;
1771
1772
		// We'll need this, because bounce templates are stored with warning templates.
1773
		require_once(SUBSDIR . '/Moderation.subs.php');
1774
1775
		// Submitting a new one or editing an existing one then pass this request off
1776
		if (isset($this->_req->post->add) || isset($this->_req->post->save) || isset($this->_req->query->tid))
1777
		{
1778
			return $this->action_modify_bounce_templates();
1779
		}
1780
1781
		// Deleting and existing one
1782
		if (isset($this->_req->post->delete) && !empty($this->_req->post->deltpl))
1783
		{
1784
			checkSession('post');
1785
			validateToken('mod-mlt');
1786
			removeWarningTemplate($this->_req->post->deltpl, 'bnctpl');
1787
		}
1788
1789
		// This is all the information required for showing the email templates.
1790
		$listOptions = array(
1791
			'id' => 'email_bounce_template_list',
1792
			'title' => $txt['ml_bounce_templates_title'],
1793
			'items_per_page' => $modSettings['defaultMaxMessages'],
1794
			'no_items_label' => $txt['ml_bounce_templates_none'],
1795
			'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'emailtemplates', '{session_data}']),
1796
			'default_sort_col' => 'title',
1797
			'get_items' => array(
1798
				'function' => fn(int $start, int $items_per_page, string $sort): array => $this->list_getBounceTemplates($start, $items_per_page, $sort),
1799
			),
1800
			'get_count' => array(
1801
				'function' => fn() => $this->list_getBounceTemplateCount(),
1802
				'params' => array('bnctpl'),
1803
			),
1804
			'columns' => array(
1805
				'title' => array(
1806
					'header' => array(
1807
						'value' => $txt['ml_bounce_templates_name'],
1808
					),
1809
					'data' => array(
1810
						'sprintf' => array(
1811
							'format' => '<a href="' . getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'emailtemplates', 'tid' => '%1$d']) . '">%2$s</a>',
1812
							'params' => array(
1813
								'id_comment' => false,
1814
								'title' => false,
1815
								'body' => false,
1816
							),
1817
						),
1818
					),
1819
					'sort' => array(
1820
						'default' => 'template_title',
1821
						'reverse' => 'template_title DESC',
1822
					),
1823
				),
1824
				'creator' => array(
1825
					'header' => array(
1826
						'value' => $txt['ml_bounce_templates_creator'],
1827
					),
1828
					'data' => array(
1829
						'db' => 'creator',
1830
					),
1831
					'sort' => array(
1832
						'default' => 'creator_name',
1833
						'reverse' => 'creator_name DESC',
1834
					),
1835
				),
1836
				'time' => array(
1837
					'header' => array(
1838
						'value' => $txt['ml_bounce_templates_time'],
1839
					),
1840
					'data' => array(
1841
						'db' => 'time',
1842
					),
1843
					'sort' => array(
1844
						'default' => 'lc.log_time DESC',
1845
						'reverse' => 'lc.log_time',
1846
					),
1847
				),
1848
				'delete' => array(
1849
					'header' => array(
1850
						'value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />',
1851
						'style' => 'width: 4%;',
1852
						'class' => 'centertext',
1853
					),
1854
					'data' => array(
1855
						'function' => static fn($rowData) => '<input type="checkbox" name="deltpl[]" value="' . $rowData['id_comment'] . '" class="input_check" />',
1856
						'class' => 'centertext',
1857
					),
1858
				),
1859
			),
1860
			'form' => array(
1861
				'href' => getUrl('admin', ['action' => 'admin', 'area' => 'maillist', 'sa' => 'emailtemplates']),
1862
				'token' => 'mod-mlt',
1863
			),
1864
			'additional_rows' => array(
1865
				array(
1866
					'class' => 'submitbutton',
1867
					'position' => 'below_table_data',
1868
					'value' => '
1869
						<input type="submit" name="delete" value="' . $txt['ml_bounce_template_delete'] . '" onclick="return confirm(\'' . $txt['ml_bounce_template_delete_confirm'] . '\');" />
1870
						<input type="submit" name="add" value="' . $txt['ml_bounce_template_add'] . '" />',
1871
				),
1872
			),
1873
		);
1874
1875
		// Create the template list.
1876
		$context['page_title'] = $txt['ml_bounce_templates_title'];
1877
		createToken('mod-mlt');
1878
1879
		createList($listOptions);
1880
1881
		// Show the list
1882
		$context['sub_template'] = 'show_list';
1883
		$context['default_list'] = 'email_bounce_template_list';
1884
	}
1885
1886
	/**
1887
	 * Edit a 'it bounced' template.
1888
	 *
1889
	 * @uses bounce_template sub template
1890
	 */
1891
	public function action_modify_bounce_templates()
1892
	{
1893
		global $context, $txt;
1894
1895
		require_once(SUBSDIR . '/Moderation.subs.php');
1896
1897
		$context['id_template'] = isset($this->_req->query->tid) ? (int) $this->_req->query->tid : 0;
1898
		$context['is_edit'] = (bool) $context['id_template'];
1899
1900
		// Standard template things, you know the drill
1901
		$context['page_title'] = $context['is_edit'] ? $txt['ml_bounce_template_modify'] : $txt['ml_bounce_template_add'];
1902
		$context['sub_template'] = 'bounce_template';
1903
1904
		//$context[$context['admin_menu_name']]['current_subsection'] = 'templates';
1905
1906
		// Defaults to show
1907
		$context['template_data'] = array(
1908
			'title' => '',
1909
			'body' => $txt['ml_bounce_template_body_default'],
1910
			'subject' => $txt['ml_bounce_template_subject_default'],
1911
			'personal' => false,
1912
			'can_edit_personal' => true,
1913
		);
1914
1915
		// If it's an edit load it.
1916
		if ($context['is_edit'])
1917
		{
1918
			modLoadTemplate($context['id_template'], 'bnctpl');
1919
		}
1920
1921
		// Wait, we are saving?
1922
		if (isset($this->_req->post->save))
1923
		{
1924
			checkSession('post');
1925
			validateToken('mod-mlt');
1926
1927
			// To check the BBC is good...
1928
			require_once(SUBSDIR . '/Post.subs.php');
1929
1930
			// Bit of cleaning!
1931
			$template_body = trim($this->_req->post->template_body);
1932
			$template_title = trim($this->_req->post->template_title);
1933
1934
			// Need something in both boxes.
1935
			if ($template_body !== '' && $template_body !== '0' && ($template_title !== '' && $template_title !== '0'))
1936
			{
1937
				// Safety first.
1938
				$template_title = Util::htmlspecialchars($template_title);
1939
1940
				// Clean up BBC.
1941
				preparsecode($template_body);
1942
1943
				// But put line breaks back!
1944
				$template_body = strtr($template_body, array('<br />' => "\n"));
1945
1946
				// Is this personal?
1947
				$recipient_id = empty($this->_req->post->make_personal) ? 0 : $this->user->id;
1948
1949
				// Updating or adding ?
1950
				if ($context['is_edit'])
1951
				{
1952
					// Simple update...
1953
					modAddUpdateTemplate($recipient_id, $template_title, $template_body, $context['id_template'], true, 'bnctpl');
1954
1955
					// If it wasn't visible and now is they've effectively added it.
1956
					if ($context['template_data']['personal'] && !$recipient_id)
1957
					{
1958
						logAction('add_bounce_template', array('template' => $template_title));
1959
					}
1960
					// Conversely if they made it personal it's a delete.
1961
					elseif (!$context['template_data']['personal'] && $recipient_id)
1962
					{
1963
						logAction('delete_bounce_template', array('template' => $template_title));
1964
					}
1965
					// Otherwise just an edit.
1966
					else
1967
					{
1968
						logAction('modify_bounce_template', array('template' => $template_title));
1969
					}
1970
				}
1971
				else
1972
				{
1973
					modAddUpdateTemplate($recipient_id, $template_title, $template_body, $context['id_template'], false, 'bnctpl');
1974
					logAction('add_bounce_template', array('template' => $template_title));
1975
				}
1976
1977
				// Get out of town...
1978
				redirectexit('action=admin;area=maillist;sa=emailtemplates');
1979
			}
1980
			else
1981
			{
1982
				$context['warning_errors'] = array();
1983
				$context['template_data']['title'] = empty($template_title) ? '' : $template_title;
1984
				$context['template_data']['body'] = empty($template_body) ? $txt['ml_bounce_template_body_default'] : $template_body;
1985
				$context['template_data']['personal'] = !empty($this->_req->post->make_personal);
1986
1987
				if (empty($template_title))
1988
				{
1989
					$context['warning_errors'][] = $txt['ml_bounce_template_error_no_title'];
1990
				}
1991
1992
				if (empty($template_body))
1993
				{
1994
					$context['warning_errors'][] = $txt['ml_bounce_template_error_no_body'];
1995
				}
1996
			}
1997
		}
1998
1999
		createToken('mod-mlt');
2000
2001
		return true;
2002
	}
2003
2004
	/**
2005
	 * Get all the bounce templates from the system
2006
	 *
2007
	 * - Callback for createList()
2008
	 *
2009
	 * @param int $start The item to start with (for pagination purposes)
2010
	 * @param int $items_per_page The number of items to show per page
2011
	 * @param string $sort A string indicating how to sort the results
2012
	 *
2013
	 * @return array
2014
	 */
2015
	public function list_getBounceTemplates($start, $items_per_page, $sort)
2016
	{
2017
		return warningTemplates($start, $items_per_page, $sort, 'bnctpl');
2018
	}
2019
2020
	/**
2021
	 * Get the number of bounce templates in the system
2022
	 *
2023
	 * - Callback for createList() to warningTemplateCount
2024
	 */
2025
	public function list_getBounceTemplateCount()
2026
	{
2027
		return warningTemplateCount('bnctpl');
2028
	}
2029
2030
	/**
2031
	 * Get the number of unapproved emails
2032
	 *
2033
	 * - Callback for createList() to list_maillist_unapproved
2034
	 *
2035
	 * @param int $start The item to start with (for pagination purposes)
2036
	 * @param int $items_per_page The number of items to show per page
2037
	 * @param string $sort A string indicating how to sort the results
2038
	 * @param int $id = 0
2039
	 *
2040
	 * @return array
2041
	 */
2042
	public function list_maillist_unapproved($start, $items_per_page, $sort = '', $id = 0)
2043
	{
2044
		return list_maillist_unapproved($id, $start, $items_per_page, $sort);
2045
	}
2046
}
2047