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