ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilMailFormGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
27 
32 {
33  final public const string MAIL_FORM_TYPE_ATTACH = 'attach';
34  final public const string MAIL_FORM_TYPE_SEARCH_RESULT = 'search_res';
35  final public const string MAIL_FORM_TYPE_NEW = 'new';
36  final public const string MAIL_FORM_TYPE_ROLE = 'role';
37  final public const string MAIL_FORM_TYPE_REPLY = 'reply';
38  final public const string MAIL_FORM_TYPE_ADDRESS = 'address';
39  final public const string MAIL_FORM_TYPE_FORWARD = 'forward';
40  final public const string MAIL_FORM_TYPE_DRAFT = 'draft';
41 
42  private readonly ilGlobalTemplateInterface $tpl;
43  private readonly ilCtrlInterface $ctrl;
44  private readonly ilLanguage $lng;
45  private readonly ilObjUser $user;
46  private readonly ilTabsGUI $tabs;
47  private readonly ilToolbarGUI $toolbar;
48  private readonly ilFormatMail $umail;
49  private readonly ilMailbox $mbox;
50  private readonly ilFileDataMail $mfile;
51  private readonly GlobalHttpState $http;
52  private readonly Refinery $refinery;
53  private ?array $request_attachments = null;
55  private readonly ilMailBodyPurifier $purifier;
56  private string $mail_form_type = '';
57  private readonly Factory $ui_factory;
58 
59  public function __construct(
60  ?ilMailTemplateService $template_service = null,
61  ?ilMailBodyPurifier $body_purifier = null
62  ) {
63  global $DIC;
64 
65  $this->template_service = $template_service ?? $DIC->mail()->textTemplates();
66  $this->tpl = $DIC->ui()->mainTemplate();
67  $this->ctrl = $DIC->ctrl();
68  $this->lng = $DIC->language();
69  $this->user = $DIC->user();
70  $this->tabs = $DIC->tabs();
71  $this->toolbar = $DIC->toolbar();
72  $this->http = $DIC->http();
73  $this->refinery = $DIC->refinery();
74  $this->umail = new ilFormatMail($this->user->getId());
75  $this->mfile = new ilFileDataMail($this->user->getId());
76  $this->mbox = new ilMailbox($this->user->getId());
77  $this->purifier = $body_purifier ?? new ilMailBodyPurifier();
78  $this->ui_factory = $DIC->ui()->factory();
79 
80  $mail_obj_id = $this->getBodyParam(
81  'mobj_id',
82  $this->refinery->kindlyTo()->int(),
83  $this->getQueryParam(
84  'mobj_id',
85  $this->refinery->kindlyTo()->int(),
86  0
87  )
88  );
89 
90  if ($mail_obj_id === 0) {
91  $mail_obj_id = $this->mbox->getInboxFolder();
92  }
93 
94  $this->ctrl->setParameter($this, 'mobj_id', $mail_obj_id);
95  }
96 
97  private function getQueryParam(string $name, Transformation $trafo, $default = null)
98  {
99  if ($this->http->wrapper()->query()->has($name)) {
100  return $this->http->wrapper()->query()->retrieve(
101  $name,
102  $trafo
103  );
104  }
105 
106  return $default;
107  }
108 
109  private function getBodyParam(string $name, Transformation $trafo, $default = null)
110  {
111  if ($this->http->wrapper()->post()->has($name)) {
112  return $this->http->wrapper()->post()->retrieve(
113  $name,
114  $trafo
115  );
116  }
117 
118  return $default;
119  }
120 
121  public function executeCommand(): void
122  {
123  $forward_class = $this->ctrl->getNextClass($this) ?? '';
124  switch (strtolower($forward_class)) {
125  case strtolower(ilMailAttachmentGUI::class):
126  $this->ctrl->setReturn($this, 'returnFromAttachments');
127  $gui = new ilMailAttachmentGUI();
128  $gui->consume();
129  $this->ctrl->forwardCommand($gui);
130  break;
131 
132  case strtolower(ilMailSearchGUI::class):
133  $this->ctrl->setReturn($this, 'searchResults');
134  $this->ctrl->forwardCommand(new ilMailSearchGUI());
135  break;
136 
137  case strtolower(ilMailSearchCoursesGUI::class):
138  $this->ctrl->setReturn($this, 'searchResults');
139  $this->ctrl->forwardCommand(new ilMailSearchCoursesGUI());
140  break;
141 
142  case strtolower(ilMailingListsGUI::class):
143  $this->ctrl->setReturn($this, 'searchResults');
144  $this->ctrl->forwardCommand(new ilMailingListsGUI());
145  break;
146 
147  case strtolower(ilMailSearchGroupsGUI::class):
148  $this->ctrl->setReturn($this, 'searchResults');
149  $this->ctrl->forwardCommand(new ilMailSearchGroupsGUI());
150  break;
151 
152  default:
153  if (!($cmd = $this->ctrl->getCmd())) {
154  $cmd = 'showForm';
155  }
156 
157  $this->$cmd();
158  break;
159  }
160  }
161 
166  protected function decodeAttachmentFiles(array $files): array
167  {
168  $decoded_files = [];
169  foreach ($files as $value) {
170  if (is_file($this->mfile->getMailPath() . '/' . $this->user->getId() . '_' . urldecode($value))) {
171  $decoded_files[] = urldecode($value);
172  }
173  }
174 
175  return $decoded_files;
176  }
177 
178  public function sendMessage(): void
179  {
180  $message = $this->getBodyParam('m_message', $this->refinery->kindlyTo()->string(), '');
181 
182  $mail_body = new ilMailBody($message, $this->purifier);
183 
184  $sanitized_message = $mail_body->getContent();
185 
186  $attachments = $this->getBodyParam(
187  'attachments',
188  $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->string()),
189  []
190  );
191  $files = $this->decodeAttachmentFiles($attachments);
192 
193  $mailer = $this->umail
194  ->withContextId(ilMailFormCall::getContextId() ?: '')
195  ->withContextParameters(ilMailFormCall::getContextParameters());
196 
197  $mailer->setSaveInSentbox(true);
198 
199  $mailer->autoresponder()->enableAutoresponder();
200 
201  if ($errors = $mailer->enqueue(
202  ilUtil::securePlainString($this->getBodyParam('rcp_to', $this->refinery->kindlyTo()->string(), '')),
203  ilUtil::securePlainString($this->getBodyParam('rcp_cc', $this->refinery->kindlyTo()->string(), '')),
204  ilUtil::securePlainString($this->getBodyParam('rcp_bcc', $this->refinery->kindlyTo()->string(), '')),
205  ilUtil::securePlainString($this->getBodyParam('m_subject', $this->refinery->kindlyTo()->string(), '')),
206  $sanitized_message,
207  $files,
208  $this->getBodyParam('use_placeholders', $this->refinery->kindlyTo()->bool(), false)
209  )) {
210  $this->request_attachments = $files;
211  $this->showSubmissionErrors($errors);
212  } else {
213  $mailer->autoresponder()->disableAutoresponder();
214 
215  $mailer->persistToStage(
216  $this->user->getId(),
217  [],
218  '',
219  '',
220  '',
221  '',
222  ''
223  );
224 
225  $this->ctrl->setParameterByClass(ilMailGUI::class, 'type', 'message_sent');
226 
228  $this->tpl->setOnScreenMessage('success', $this->lng->txt('mail_message_send'), true);
229  $this->ctrl->redirectToURL(ilMailFormCall::getRefererRedirectUrl());
230  } else {
231  $this->ctrl->redirectByClass(ilMailGUI::class);
232  }
233  }
234  $mailer->autoresponder()->disableAutoresponder();
235 
236  $this->showForm();
237  }
238 
239  public function saveDraft(): void
240  {
241  $draft_folder_id = $this->mbox->getDraftsFolder();
242 
243  $files = $this->decodeAttachmentFiles($this->getBodyParam(
244  'attachments',
245  $this->refinery->kindlyTo()->listOf(
246  $this->refinery->custom()->transformation($this->refinery->kindlyTo()->string())
247  ),
248  []
249  ));
250 
251  $rcp_to = ilUtil::securePlainString($this->getBodyParam('rcp_to', $this->refinery->kindlyTo()->string(), ''));
252  $rcp_cc = ilUtil::securePlainString($this->getBodyParam('rcp_cc', $this->refinery->kindlyTo()->string(), ''));
253  $rcp_bcc = ilUtil::securePlainString($this->getBodyParam('rcp_bcc', $this->refinery->kindlyTo()->string(), ''));
254 
255  if ($errors = $this->umail->validateRecipients(
256  $rcp_to,
257  $rcp_cc,
258  $rcp_bcc,
259  )) {
260  $this->request_attachments = $files;
261  $this->showSubmissionErrors($errors);
262  $this->showForm();
263  return;
264  }
265 
266  if (ilSession::get('draft')) {
267  $draft_id = (int) ilSession::get('draft');
268  ilSession::clear('draft');
269  } else {
270  $draft_id = $this->umail->getNewDraftId($draft_folder_id);
271  }
272 
273  $this->umail->updateDraft(
274  $draft_folder_id,
275  $files,
276  $rcp_to,
277  $rcp_cc,
278  $rcp_bcc,
280  $this->getBodyParam('m_subject', $this->refinery->kindlyTo()->string(), '')
281  ) ?: 'No Subject',
282  ilUtil::securePlainString($this->getBodyParam('m_message', $this->refinery->kindlyTo()->string(), '')),
283  $draft_id,
284  $this->getBodyParam('use_placeholders', $this->refinery->kindlyTo()->bool(), false),
287  );
288 
289  $this->tpl->setOnScreenMessage('info', $this->lng->txt('mail_saved'), true);
290 
293  } else {
294  $this->ctrl->redirectByClass([ilMailGUI::class, ilMailFolderGUI::class]);
295  }
296 
297  $this->showForm();
298  }
299 
300  public function searchUsers(bool $save = true): void
301  {
302  $this->tpl->setTitle($this->lng->txt('mail'));
303 
304  if ($save) {
305  $files = $this->getBodyParam(
306  'attachments',
307  $this->refinery->kindlyTo()->listOf(
308  $this->refinery->custom()->transformation(function ($elm): string {
309  $attachment = $this->refinery->kindlyTo()->string()->transform($elm);
310 
311  return urldecode($attachment);
312  })
313  ),
314  []
315  );
316 
317  // Note: For security reasons, ILIAS only allows Plain text strings in E-Mails.
318  $this->umail->persistToStage(
319  $this->user->getId(),
320  $files,
321  ilUtil::securePlainString($this->getBodyParam('rcp_to', $this->refinery->kindlyTo()->string(), '')),
322  ilUtil::securePlainString($this->getBodyParam('rcp_cc', $this->refinery->kindlyTo()->string(), '')),
323  ilUtil::securePlainString($this->getBodyParam('rcp_bcc', $this->refinery->kindlyTo()->string(), '')),
324  ilUtil::securePlainString($this->getBodyParam('m_subject', $this->refinery->kindlyTo()->string(), '')),
325  ilUtil::securePlainString($this->getBodyParam('m_message', $this->refinery->kindlyTo()->string(), '')),
326  $this->getBodyParam('use_placeholders', $this->refinery->kindlyTo()->bool(), false),
329  );
330  }
331 
332  $form = new ilPropertyFormGUI();
333  $form->setId('search_rcp');
334  $form->setTitle($this->lng->txt('search_recipients'));
335  $form->setFormAction($this->ctrl->getFormAction($this, 'search'));
336 
337  $inp = new ilTextInputGUI($this->lng->txt('search_for'), 'search');
338  $inp->setSize(30);
339  $data_source_url = $this->ctrl->getLinkTarget($this, 'lookupRecipientAsync', '', true);
340  $inp->setDataSource($data_source_url);
341 
342  $search_query = trim((string) ilSession::get('mail_search_search'));
343  if ($search_query !== '') {
344  $inp->setValue(ilLegacyFormElementsUtil::prepareFormOutput($search_query, true));
345  }
346  $form->addItem($inp);
347 
348  $form->addCommandButton('search', $this->lng->txt('search'));
349  $form->addCommandButton('cancelSearch', $this->lng->txt('cancel'));
350 
351  $this->tpl->setContent($form->getHTML());
352  $this->tpl->printToStdout();
353  }
354 
355  public function searchCoursesTo(): void
356  {
357  $this->saveMailBeforeSearch();
358 
359  if (ilSession::get('search_crs')) {
360  $this->ctrl->setParameterByClass('ilmailsearchcoursesgui', 'cmd', 'showMembers');
361  }
362 
363  $this->ctrl->setParameterByClass(ilMailSearchCoursesGUI::class, 'ref', 'mail');
364  $this->ctrl->redirectByClass(ilMailSearchCoursesGUI::class);
365  }
366 
367  public function searchGroupsTo(): void
368  {
369  $this->saveMailBeforeSearch();
370 
371  $this->ctrl->setParameterByClass(ilMailSearchGroupsGUI::class, 'ref', 'mail');
372  $this->ctrl->redirectByClass(ilMailSearchGroupsGUI::class);
373  }
374 
375  public function search(): void
376  {
378  'mail_search_search',
379  ilUtil::securePlainString($this->getBodyParam('search', $this->refinery->kindlyTo()->string(), ''))
380  );
381 
382  if (trim(ilSession::get('mail_search_search') ?? '') === '') {
383  $this->tpl->setOnScreenMessage('info', $this->lng->txt('mail_insert_query'));
384  $this->searchUsers(false);
385  } elseif (strlen(trim(ilSession::get('mail_search_search') ?? '')) < 3) {
386  $this->lng->loadLanguageModule('search');
387  $this->tpl->setOnScreenMessage('info', $this->lng->txt('search_minimum_three'));
388  $this->searchUsers(false);
389  } else {
390  $this->ctrl->setParameterByClass(
391  ilMailSearchGUI::class,
392  'search',
393  urlencode(ilSession::get('mail_search_search') ?? '')
394  );
395  $this->ctrl->redirectByClass(ilMailSearchGUI::class);
396  }
397  }
398 
399  public function cancelSearch(): void
400  {
401  ilSession::clear('mail_search');
402  $this->searchResults();
403  }
404 
405  public function editAttachments(): void
406  {
407  $files = $this->getBodyParam(
408  'attachments',
409  $this->refinery->kindlyTo()->listOf(
410  $this->refinery->custom()->transformation(function ($elm): string {
411  $attachment = $this->refinery->kindlyTo()->string()->transform($elm);
412 
413  return urldecode($attachment);
414  })
415  ),
416  []
417  );
418 
419  // Note: For security reasons, ILIAS only allows Plain text strings in E-Mails.
420  $this->umail->persistToStage(
421  $this->user->getId(),
422  $files,
423  ilUtil::securePlainString($this->getBodyParam('rcp_to', $this->refinery->kindlyTo()->string(), '')),
424  ilUtil::securePlainString($this->getBodyParam('rcp_cc', $this->refinery->kindlyTo()->string(), '')),
425  ilUtil::securePlainString($this->getBodyParam('rcp_bcc', $this->refinery->kindlyTo()->string(), '')),
426  ilUtil::securePlainString($this->getBodyParam('m_subject', $this->refinery->kindlyTo()->string(), '')),
427  ilUtil::securePlainString($this->getBodyParam('m_message', $this->refinery->kindlyTo()->string(), '')),
428  $this->getBodyParam('use_placeholders', $this->refinery->kindlyTo()->bool(), false),
431  );
432 
433  $this->ctrl->redirectByClass(ilMailAttachmentGUI::class);
434  }
435 
436  public function returnFromAttachments(): void
437  {
438  $this->mail_form_type = self::MAIL_FORM_TYPE_ATTACH;
439  $this->showForm();
440  }
441 
442  public function searchResults(): void
443  {
444  $this->mail_form_type = self::MAIL_FORM_TYPE_SEARCH_RESULT;
445  $this->showForm();
446  }
447 
448  public function mailUser(): void
449  {
450  $this->mail_form_type = self::MAIL_FORM_TYPE_NEW;
451  $this->showForm();
452  }
453 
454  public function mailRole(): void
455  {
456  $this->mail_form_type = self::MAIL_FORM_TYPE_ROLE;
457  $this->showForm();
458  }
459 
460  public function replyMail(): void
461  {
462  $this->mail_form_type = self::MAIL_FORM_TYPE_REPLY;
463  $this->showForm();
464  }
465 
466  public function mailAttachment(): void
467  {
468  $this->mail_form_type = self::MAIL_FORM_TYPE_ATTACH;
469  $this->showForm();
470  }
471 
472  protected function getTemplateDataById(): void
473  {
474  if (!$this->http->wrapper()->query()->has('template_id')) {
475  $this->http->close();
476  }
477 
478  try {
479  $template = $this->template_service->loadTemplateForId(
480  $this->http->wrapper()->query()->retrieve('template_id', $this->refinery->kindlyTo()->int())
481  );
483 
484  $this->http->saveResponse(
485  $this->http->response()
486  ->withHeader(ResponseHeader::CONTENT_TYPE, 'application/json')
487  ->withBody(Streams::ofString(json_encode([
488  'm_subject' => $template->getSubject(),
489  'm_message' => $this->umail->appendSignature($template->getMessage()),
490  ], JSON_THROW_ON_ERROR)))
491  );
492  } catch (Exception) {
493  }
494 
495  $this->http->sendResponse();
496  $this->http->close();
497  }
498 
499  public function showForm(): void
500  {
501  $this->tpl->addBlockFile(
502  'ADM_CONTENT',
503  'adm_content',
504  'tpl.mail_new.html',
505  'components/ILIAS/Mail'
506  );
507  $this->tpl->setTitle($this->lng->txt('mail'));
508 
509  $this->lng->loadLanguageModule('crs');
510 
512  $this->tabs->setBackTarget(
513  $this->lng->txt('back'),
514  $this->ctrl->getLinkTarget($this, 'cancelMail')
515  );
516  }
517 
518  $mail_data = [];
519  $mail_data['rcp_to'] = '';
520  $mail_data['rcp_cc'] = '';
521  $mail_data['rcp_bcc'] = '';
522  $mail_data['attachments'] = [];
523 
524  $mail_id = $this->getQueryParam('mail_id', $this->refinery->kindlyTo()->int(), 0);
525  $type = $this->getQueryParam('type', $this->refinery->kindlyTo()->string(), '');
526  if ($this->mail_form_type !== '') {
527  $type = $this->mail_form_type;
528  }
529 
530  switch ($type) {
531  case self::MAIL_FORM_TYPE_REPLY:
532  $mail_data = $this->umail->getMail($mail_id);
533 
534  $mail_data['m_subject'] = $this->umail->formatReplySubject($mail_data['m_subject'] ?? '');
535  $mail_data['m_message'] = $this->umail->prependSignature(
536  $this->umail->formatReplyMessage($mail_data['m_message'] ?? '')
537  );
538  $mail_data['attachments'] = [];
539  $mail_data['rcp_cc'] = '';
540  $mail_data['rcp_to'] = $this->umail->formatReplyRecipient();
541  break;
542 
543  case self::MAIL_FORM_TYPE_SEARCH_RESULT:
544  $mail_data = $this->umail->retrieveFromStage();
545 
546  if (ilSession::get('mail_search_results_to')) {
547  $mail_data = $this->umail->appendSearchResult(
548  $this->refinery->kindlyTo()->listOf(
549  $this->refinery->kindlyTo()->string()
550  )->transform(ilSession::get('mail_search_results_to')),
551  'to'
552  );
553  }
554  if (ilSession::get('mail_search_results_cc')) {
555  $mail_data = $this->umail->appendSearchResult(
556  $this->refinery->kindlyTo()->listOf(
557  $this->refinery->kindlyTo()->string()
558  )->transform(ilSession::get('mail_search_results_cc')),
559  'cc'
560  );
561  }
562  if (ilSession::get('mail_search_results_bcc')) {
563  $mail_data = $this->umail->appendSearchResult(
564  $this->refinery->kindlyTo()->listOf(
565  $this->refinery->kindlyTo()->string()
566  )->transform(ilSession::get('mail_search_results_bcc')),
567  'bc'
568  );
569  }
570 
571  ilSession::clear('mail_search_results_to');
572  ilSession::clear('mail_search_results_cc');
573  ilSession::clear('mail_search_results_bcc');
574  break;
575 
576  case self::MAIL_FORM_TYPE_ATTACH:
577  $mail_data = $this->umail->retrieveFromStage();
578  break;
579 
580  case self::MAIL_FORM_TYPE_DRAFT:
581  ilSession::set('draft', $mail_id);
582  $mail_data = $this->umail->getMail($mail_id);
583  ilMailFormCall::setContextId($mail_data['tpl_ctx_id']);
584  ilMailFormCall::setContextParameters($mail_data['tpl_ctx_params']);
585  break;
586 
587  case self::MAIL_FORM_TYPE_FORWARD:
588  $mail_data = $this->umail->getMail($mail_id);
589  $mail_data['rcp_to'] = $mail_data['rcp_cc'] = $mail_data['rcp_bcc'] = '';
590  $mail_data['m_subject'] = $this->umail->formatForwardSubject($mail_data['m_subject'] ?? '');
591  $mail_data['m_message'] = $this->umail->prependSignature($mail_data['m_message'] ?? '');
592  if (is_array($mail_data['attachments']) && count($mail_data['attachments']) && $error = $this->mfile->adoptAttachments(
593  $mail_data['attachments'],
594  $mail_id
595  )) {
596  $this->tpl->setOnScreenMessage('info', $error);
597  }
598  break;
599 
600  case self::MAIL_FORM_TYPE_NEW:
601  // Note: For security reasons, ILIAS only allows Plain text strings in E-Mails.
602  $to = ilUtil::securePlainString($this->getQueryParam('rcp_to', $this->refinery->kindlyTo()->string(), ''));
603  if ($to === '' && ilSession::get('rcp_to')) {
604  $to = ilSession::get('rcp_to');
605  }
606  $mail_data['rcp_to'] = $to;
607 
608  $cc = ilUtil::securePlainString($this->getQueryParam('rcp_cc', $this->refinery->kindlyTo()->string(), ''));
609  if ($cc === '' && ilSession::get('rcp_cc')) {
610  $cc = ilSession::get('rcp_cc');
611  }
612  $mail_data['rcp_cc'] = $cc;
613 
614  $bcc = ilUtil::securePlainString($this->getQueryParam('rcp_bcc', $this->refinery->kindlyTo()->string(), ''));
615  if ($bcc === '' && ilSession::get('rcp_bcc')) {
616  $bcc = ilSession::get('rcp_bcc');
617  }
618  $mail_data['rcp_bcc'] = $bcc;
619 
620  $mail_data['m_message'] = '';
621  if (($sig = ilMailFormCall::getSignature()) !== '') {
622  $mail_data['m_message'] = $sig;
623  $mail_data['m_message'] .= chr(13)
624  . chr(10)
625  . chr(13)
626  . chr(10);
627  }
628  $mail_data['m_message'] .= $this->umail->appendSignature('');
629 
630  ilSession::set('rcp_to', '');
631  ilSession::set('rcp_cc', '');
632  ilSession::set('rcp_bcc', '');
633  break;
634 
635  case self::MAIL_FORM_TYPE_ROLE:
636  $roles = [];
637  if ($this->http->wrapper()->post()->has('roles')) {
638  $roles = $this->http->wrapper()->post()->retrieve(
639  'roles',
640  $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->string())
641  );
642  } elseif (is_array(ilSession::get('mail_roles'))) {
643  $roles = $this->refinery->kindlyTo()->listOf(
644  $this->refinery->kindlyTo()->string()
645  )->transform(ilSession::get('mail_roles'));
646  }
647 
648  // Note: For security reasons, ILIAS only allows Plain text strings in E-Mails.
649  $mail_data['rcp_to'] = ilUtil::securePlainString(
650  implode(',', $roles)
651  );
652 
653  $mail_data['m_message'] = '';
654  if (($sig = ilMailFormCall::getSignature()) !== '') {
655  $mail_data['m_message'] = $sig;
656  $mail_data['m_message'] .= chr(13)
657  . chr(10)
658  . chr(13)
659  . chr(10);
660  }
661 
662  $additional_msg_text = '';
663  if ($this->http->wrapper()->post()->has('additional_message_text')) {
664  $additional_msg_text = ilUtil::securePlainString($this->http->wrapper()->post()->retrieve(
665  'additional_message_text',
666  $this->refinery->kindlyTo()->string()
667  ));
668  }
669 
670  $mail_data['m_message'] .= $additional_msg_text
671  . chr(13)
672  . chr(10)
673  . $this->umail->appendSignature('');
674  ilSession::set('mail_roles', []);
675  break;
676 
677  case self::MAIL_FORM_TYPE_ADDRESS:
678  $rcp = '';
679  if ($this->http->wrapper()->query()->has('rcp')) {
680  $rcp = $this->http->wrapper()->query()->retrieve('rcp', $this->refinery->kindlyTo()->string());
681  }
682  $mail_data['rcp_to'] = urldecode((string) $rcp);
683  break;
684 
685  default:
686  $mail_data = $this->http->request()->getParsedBody();
687  foreach ($mail_data as $key => $value) {
688  if (is_string($value)) {
689  // Note: For security reasons, ILIAS only allows Plain text strings in E-Mails.
690  $mail_data[$key] = ilUtil::securePlainString($value);
691  }
692  }
693 
694  if ($this->request_attachments) {
695  $mail_data['attachments'] = $this->request_attachments;
696  }
697  break;
698  }
699 
700  $form_gui = new ilPropertyFormGUI();
701  $form_gui->setTitle($this->lng->txt('compose'));
702  $form_gui->setId('mail_compose_form');
703  $form_gui->setName('mail_compose_form');
704  $form_gui->setFormAction($this->ctrl->getFormAction($this, 'sendMessage'));
705 
706  $this->tpl->setVariable('FORM_ID', $form_gui->getId());
707 
708  $mail_form = 'form_' . $form_gui->getName();
709 
710  $btn = $this->ui_factory->button()
711  ->standard($this->lng->txt('search_recipients'), '#')
712  ->withOnLoadCode(static fn($id): string => "
713  document.getElementById('$id').addEventListener('click', function() {
714  const frm = document.getElementById('$mail_form'),
715  action = new URL(frm.action),
716  action_params = new URLSearchParams(action.search);
717 
718  action_params.delete('cmd');
719  action_params.append('cmd', 'searchUsers');
720 
721  action.search = action_params.toString();
722 
723  frm.action = action.href;
724  frm.submit();
725  return false;
726  });
727  ");
728  $this->toolbar->addStickyItem($btn);
729 
730  $btn = $this->ui_factory->button()
731  ->standard($this->lng->txt('mail_my_courses'), '#')
732  ->withOnLoadCode(static fn($id): string => "
733  document.getElementById('$id').addEventListener('click', function() {
734  const frm = document.getElementById('$mail_form'),
735  action = new URL(frm.action),
736  action_params = new URLSearchParams(action.search);
737 
738  action_params.delete('cmd');
739  action_params.append('cmd', 'searchCoursesTo');
740 
741  action.search = action_params.toString();
742 
743  frm.action = action.href;
744  frm.submit();
745  return false;
746  });
747  ");
748  $this->toolbar->addComponent($btn);
749 
750  $btn = $this->ui_factory->button()
751  ->standard($this->lng->txt('mail_my_groups'), '#')
752  ->withOnLoadCode(static fn($id): string => "
753  document.getElementById('$id').addEventListener('click', function() {
754  const frm = document.getElementById('$mail_form'),
755  action = new URL(frm.action),
756  action_params = new URLSearchParams(action.search);
757 
758  action_params.delete('cmd');
759  action_params.append('cmd', 'searchGroupsTo');
760 
761  action.search = action_params.toString();
762 
763  frm.action = action.href;
764  frm.submit();
765  return false;
766  });
767  ");
768  $this->toolbar->addComponent($btn);
769 
770  if (count(ilBuddyList::getInstanceByGlobalUser()->getLinkedRelations()) > 0) {
771  $btn = $this->ui_factory->button()
772  ->standard($this->lng->txt('mail_my_mailing_lists'), '#')
773  ->withOnLoadCode(static fn($id): string => "
774  document.getElementById('$id').addEventListener('click', function() {
775  const frm = document.getElementById('$mail_form'),
776  action = new URL(frm.action),
777  action_params = new URLSearchParams(action.search);
778 
779  action_params.delete('cmd');
780  action_params.append('cmd', 'searchMailingListsTo');
781 
782  action.search = action_params.toString();
783 
784  frm.action = action.href;
785  frm.submit();
786  return false;
787  });
788  ");
789  $this->toolbar->addComponent($btn);
790  }
791 
792  $data_source_url = $this->ctrl->getLinkTarget($this, 'lookupRecipientAsync', '', true);
793 
794  $inp = new ilTextInputGUI($this->lng->txt('mail_to'), 'rcp_to');
795  $inp->setMaxLength(null);
796  $inp->setRequired(true);
797  $inp->setSize(50);
798  $inp->setValue((string) ($mail_data['rcp_to'] ?? ''));
799  $inp->setDataSource($data_source_url, ',');
800  $form_gui->addItem($inp);
801 
802  $inp = new ilTextInputGUI($this->lng->txt('mail_cc'), 'rcp_cc');
803  $inp->setMaxLength(null);
804  $inp->setSize(50);
805  $inp->setValue((string) ($mail_data['rcp_cc'] ?? ''));
806  $inp->setDataSource($data_source_url, ',');
807  $form_gui->addItem($inp);
808 
809  $inp = new ilTextInputGUI($this->lng->txt('mail_bcc'), 'rcp_bcc');
810  $inp->setMaxLength(null);
811  $inp->setSize(50);
812  $inp->setValue($mail_data['rcp_bcc'] ?? '');
813  $inp->setDataSource($data_source_url, ',');
814  $form_gui->addItem($inp);
815 
816  $inp = new ilTextInputGUI($this->lng->txt('subject'), 'm_subject');
817  $inp->setSize(50);
818  $inp->setRequired(true);
819  $inp->setValue((string) ($mail_data['m_subject'] ?? ''));
820  $form_gui->addItem($inp);
821 
823  $this->lng->txt(
824  isset($mail_data['attachments']) && is_array($mail_data['attachments']) ?
825  'edit' :
826  'add'
827  ),
828  'm_attachment'
829  );
830  if (isset($mail_data['attachments']) && is_array($mail_data['attachments'])) {
831  foreach ($mail_data['attachments'] as $data) {
832  if (is_file($this->mfile->getMailPath() . '/' . $this->user->getId() . '_' . $data)) {
833  $hidden = new ilHiddenInputGUI('attachments[]');
834  $form_gui->addItem($hidden);
835  $size = filesize($this->mfile->getMailPath() . '/' . $this->user->getId() . '_' . $data);
836  $label = $data . ' [' . ilUtil::formatSize($size) . ']';
837  $att->addItem($label);
838  $hidden->setValue(urlencode((string) $data));
839  }
840  }
841  }
842  $form_gui->addItem($att);
843 
846  $context_id = ilMailFormCall::getContextId();
847 
848  $mail_data['use_placeholders'] = true;
849 
850  try {
852 
853  $templates = $this->template_service->loadTemplatesForContextId($context->getId());
854  if ($templates !== []) {
855  $options = [];
856 
857  $template_chb = new ilMailTemplateSelectInputGUI(
858  $this->lng->txt('mail_template_client'),
859  'template_id',
860  $this->ctrl->getLinkTarget($this, 'getTemplateDataById', '', true),
861  ['m_subject' => false, 'm_message' => true]
862  );
863 
864  foreach ($templates as $template) {
865  $options[$template->getTplId()] = $template->getTitle();
866 
867  if (!isset($mail_data['template_id']) && $template->isDefault()) {
868  $template_chb->setValue((string) $template->getTplId());
869  $form_gui->getItemByPostVar('m_subject')->setValue($template->getSubject());
870  $mail_data['m_message'] = $template->getMessage() . $this->umail->appendSignature(
871  $mail_data['m_message']
872  );
873  }
874  }
875  if (isset($mail_data['template_id'])) {
876  $template_chb->setValue((string) ((int) $mail_data['template_id']));
877  }
878  asort($options);
879 
880  $template_chb->setInfo($this->lng->txt('mail_template_client_info'));
881  $template_chb->setOptions(['' => $this->lng->txt('please_choose')] + $options);
882  $form_gui->addItem($template_chb);
883  }
884  } catch (Exception) {
885  ilLoggerFactory::getLogger('mail')->error(sprintf(
886  '%s has been called with invalid context id: %s.',
887  __METHOD__,
888  $context_id
889  ));
890  }
891  }
892 
893  $inp = new ilTextAreaInputGUI($this->lng->txt('message_content'), 'm_message');
894  $inp->setValue((string) ($mail_data['m_message'] ?? ''));
895  $inp->setRequired(false);
896  $inp->setCols(60);
897  $inp->setRows(10);
898  $form_gui->addItem($inp);
899 
900  $chb = new ilCheckboxInputGUI(
901  $this->lng->txt('mail_serial_letter_placeholders'),
902  'use_placeholders'
903  );
904  $chb->setValue('1');
905  $chb->setChecked(isset($mail_data['use_placeholders']) && $mail_data['use_placeholders']);
906 
907  $placeholders = new ilManualPlaceholderInputGUI(
908  $this->lng->txt('mail_form_placeholders_label'),
909  'm_placeholders',
910  'm_message'
911  );
912  $placeholders->setInstructionText($this->lng->txt('mail_nacc_use_placeholder'));
913  try {
914  $placeholders->setAdviseText(sprintf($this->lng->txt('placeholders_advise'), '<br />'));
915  } catch (Throwable) {
916  $placeholders->setAdviseText($this->lng->txt('placeholders_advise'));
917  }
918  foreach ($context->getPlaceholders() as $key => $value) {
919  $placeholders->addPlaceholder($value['placeholder'], $value['label']);
920  }
921  $chb->addSubItem($placeholders);
922  $form_gui->addItem($chb);
923 
924  $form_gui->addCommandButton('sendMessage', $this->lng->txt('send_mail'));
925  $form_gui->addCommandButton('saveDraft', $this->lng->txt('save_message'));
927  $form_gui->addCommandButton('cancelMail', $this->lng->txt('cancel'));
928  }
929 
930  $this->tpl->parseCurrentBlock();
931 
932  $this->tpl->setVariable('FORM', $form_gui->getHTML());
933 
934  $this->tpl->addJavaScript('assets/js/ilMailComposeFunctions.js');
935  $this->tpl->printToStdout();
936  }
937 
938  public function lookupRecipientAsync(): void
939  {
940  $search = trim((string) $this->getBodyParam(
941  'term',
942  $this->refinery->kindlyTo()->string(),
943  $this->getQueryParam(
944  'term',
945  $this->refinery->kindlyTo()->string(),
946  ''
947  )
948  ));
949 
950  $result = [];
951 
952  if (ilStr::strLen($search) < 3) {
953  $this->http->saveResponse(
954  $this->http->response()
955  ->withHeader(ResponseHeader::CONTENT_TYPE, 'application/json')
956  ->withBody(Streams::ofString(json_encode($result, JSON_THROW_ON_ERROR)))
957  );
958 
959  $this->http->sendResponse();
960  $this->http->close();
961  }
962 
963  // #14768
964  $quoted = ilUtil::stripSlashes($search);
965  $quoted = str_replace(['%', '_'], ['\%', '\_'], $quoted);
966 
967  $form = new ilMailForm();
968  $result = $form->getRecipientAsync('%' . $quoted . '%', ilUtil::stripSlashes($search));
969 
970  $this->http->saveResponse(
971  $this->http->response()
972  ->withHeader(ResponseHeader::CONTENT_TYPE, 'application/json')
973  ->withBody(Streams::ofString(json_encode($result, JSON_THROW_ON_ERROR)))
974  );
975  $this->http->sendResponse();
976  $this->http->close();
977  }
978 
979  public function cancelMail(): void
980  {
983  }
984 
985  $this->showForm();
986  }
987 
988  protected function saveMailBeforeSearch(): void
989  {
990  $files = $this->getBodyParam(
991  'attachments',
992  $this->refinery->kindlyTo()->listOf(
993  $this->refinery->custom()->transformation(function ($elm): string {
994  $attachment = $this->refinery->kindlyTo()->string()->transform($elm);
995 
996  return urldecode($attachment);
997  })
998  ),
999  []
1000  );
1001 
1002  $this->umail->persistToStage(
1003  $this->user->getId(),
1004  $files,
1005  ilUtil::securePlainString($this->getBodyParam('rcp_to', $this->refinery->kindlyTo()->string(), '')),
1006  ilUtil::securePlainString($this->getBodyParam('rcp_cc', $this->refinery->kindlyTo()->string(), '')),
1007  ilUtil::securePlainString($this->getBodyParam('rcp_bcc', $this->refinery->kindlyTo()->string(), '')),
1008  ilUtil::securePlainString($this->getBodyParam('m_subject', $this->refinery->kindlyTo()->string(), '')),
1009  ilUtil::securePlainString($this->getBodyParam('m_message', $this->refinery->kindlyTo()->string(), '')),
1010  $this->getBodyParam('use_placeholders', $this->refinery->kindlyTo()->bool(), false),
1013  );
1014  }
1015 
1016  public function searchMailingListsTo(): void
1017  {
1018  $this->saveMailBeforeSearch();
1019 
1020  $this->ctrl->setParameterByClass(ilMailingListsGUI::class, 'ref', 'mail');
1021  $this->ctrl->redirectByClass(ilMailingListsGUI::class);
1022  }
1023 
1027  protected function showSubmissionErrors(array $errors): void
1028  {
1029  $formatter = new ilMailErrorFormatter($this->lng);
1030  $formatted_errors = $formatter->format($errors);
1031 
1032  if ($formatted_errors !== '') {
1033  $this->tpl->setOnScreenMessage('failure', $formatted_errors);
1034  }
1035  }
1036 }
static get(string $a_var)
decodeAttachmentFiles(array $files)
final const string MAIL_FORM_TYPE_NEW
$context
Definition: webdav.php:31
static getLogger(string $a_component_id)
Get component logger.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
readonly ilLanguage $lng
readonly ilMailbox $mbox
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
final const string MAIL_FORM_TYPE_REPLY
readonly ilFileDataMail $mfile
static prepareFormOutput($a_str, bool $a_strip=false)
readonly ilMailBodyPurifier $purifier
readonly ilFormatMail $umail
readonly ilObjUser $user
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
ilMailFormGUI: ilMailAttachmentGUI, ilMailSearchGUI, ilMailSearchCoursesGUI, ilMailSearchGroupsGUI, ilMailingListsGUI
final const string MAIL_FORM_TYPE_ADDRESS
static strLen(string $a_string)
Definition: class.ilStr.php:60
This class represents a hidden form property in a property form.
readonly ilTabsGUI $tabs
final const string MAIL_FORM_TYPE_FORWARD
readonly Factory $ui_factory
static http()
Fetches the global http state from ILIAS.
static securePlainString(string $a_str)
final const string MAIL_FORM_TYPE_ROLE
This is how the factory for UI elements looks.
Definition: Factory.php:37
searchUsers(bool $save=true)
static formatSize(int $size, string $a_mode='short', ?ilLanguage $a_lng=null)
Returns the specified file size value in a human friendly form.
readonly Refinery $refinery
global $DIC
Definition: shib_login.php:26
getQueryParam(string $name, Transformation $trafo, $default=null)
readonly ilToolbarGUI $toolbar
static setContextParameters(array $parameters)
getBodyParam(string $name, Transformation $trafo, $default=null)
static redirect(string $a_script)
final const string MAIL_FORM_TYPE_SEARCH_RESULT
showSubmissionErrors(array $errors)
final const string MAIL_FORM_TYPE_ATTACH
readonly GlobalHttpState $http
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
readonly ilCtrlInterface $ctrl
This class represents a text area property in a property form.
A transformation is a function from one datatype to another.
static setContextId(?string $id)
$message
Definition: xapiexit.php:31
final const string MAIL_FORM_TYPE_DRAFT
__construct(?ilMailTemplateService $template_service=null, ?ilMailBodyPurifier $body_purifier=null)
ilMailTemplateService $template_service
static clear(string $a_var)
static set(string $a_var, $a_val)
Set a value.
readonly ilGlobalTemplateInterface $tpl
static getInstanceByGlobalUser(?ilObjUser $user=null)