1: <?php
2:
3: /**
4: * SMTP modules
5: * @package modules
6: * @subpackage smtp
7: */
8:
9: if (!defined('DEBUG_MODE')) { die(); }
10:
11: use League\CommonMark\GithubFlavoredMarkdownConverter;
12:
13: define('MAX_RECIPIENT_WARNING', 20);
14: require_once APP_PATH.'modules/smtp/functions.php';
15: require APP_PATH.'modules/smtp/hm-smtp.php';
16: require APP_PATH.'modules/smtp/hm-mime-message.php';
17:
18: /**
19: * @subpackage smtp/handler
20: */
21: class Hm_Handler_load_smtp_reply_to_details extends Hm_Handler_Module {
22: public function process() {
23: if (array_key_exists('list_path', $this->request->get) &&
24: array_key_exists('uid', $this->request->get)) {
25:
26: $cache_name = sprintf('reply_details_%s_%s',
27: $this->request->get['list_path'],
28: $this->request->get['uid']
29: );
30: $reply_details = $this->session->get($cache_name, false);
31:
32: if ($reply_details) {
33: $reply_type = get_reply_type($this->request->get);
34: if ($reply_type == 'reply_all') {
35: recip_count_check($reply_details['msg_headers'], $this);
36: }
37: $this->out('reply_details', $reply_details);
38: }
39: }
40: }
41: }
42:
43: /**
44: * @subpackage smtp/handler
45: */
46: class Hm_Handler_load_smtp_is_imap_draft extends Hm_Handler_Module {
47: public function unangle($str) {
48: return trim(preg_replace("/(^| )</", ' ', preg_replace("/>($| )/", ' ', $str)));
49: }
50: public function process() {
51: if (!$this->module_is_supported('imap')) {
52: Hm_Msgs::add('IMAP module unavailable.', 'danger');
53: return;
54: }
55: if (array_key_exists('imap_draft', $this->request->get)
56: && array_key_exists('list_path', $this->request->get)
57: && array_key_exists('uid', $this->request->get)) {
58: $path = explode('_', $this->request->get['list_path']);
59: $mailbox = Hm_IMAP_List::get_connected_mailbox($path[1]);
60: if ($mailbox && $mailbox->authed()) {
61: list ($msg_struct, $msg_struct_first, $msg_text, $part) = $mailbox->get_structured_message(hex2bin($path[2]), $this->request->get['uid'], false, true);
62: $msg_header = $mailbox->get_message_headers(hex2bin($path[2]), $this->request->get['uid']);
63: if (!array_key_exists('From', $msg_header) || count($msg_header) == 0) {
64: return;
65: }
66:
67: # Attachment Download
68: # Draft attachments must be redownloaded and added to the file cache to prevent
69: # attachments from being deleted when editing a previously saved draft.
70: $attached_files = [];
71: $this->session->set('uploaded_files', array());
72: if (array_key_exists(0, $msg_struct) && array_key_exists('subs', $msg_struct[0])) {
73: foreach ($msg_struct[0]['subs'] as $ind => $sub) {
74: if ($ind != '0.1') {
75: $new_attachment['basename'] = $sub['description'];
76: $new_attachment['name'] = $sub['description'];
77: $new_attachment['size'] = $sub['size'];
78: $new_attachment['type'] = $sub['type'];
79: $file_path = $this->config->get('attachment_dir').DIRECTORY_SEPARATOR.$new_attachment['name'];
80: $content = Hm_Crypt::ciphertext($mailbox->get_message_content(hex2bin($path[2]), $this->request->get['uid'], $ind), Hm_Request_Key::generate());
81: file_put_contents($file_path, $content);
82: $new_attachment['tmp_name'] = $file_path;
83: $new_attachment['filename'] = $file_path;
84: $attached_files[$this->request->get['uid']][] = $new_attachment;
85: }
86: }
87: }
88: $this->session->set('uploaded_files', $attached_files);
89:
90: $imap_draft = array(
91: 'From' => $msg_header['From'],
92: 'To' => $this->unangle($msg_header['To']),
93: 'Subject' => $msg_header['Subject'],
94: 'Message-Id' => $msg_header['Message-Id'],
95: 'Content-Type' => $msg_header['Content-Type'],
96: 'Body' => $msg_text,
97: 'Reply-To' => $msg_header['Reply-To']
98: );
99:
100: if (array_key_exists('Cc', $msg_header)) {
101: $imap_draft['Cc'] = $this->unangle($msg_header['Cc']);
102: }
103:
104: if ($imap_draft) {
105: recip_count_check($imap_draft, $this);
106: $this->out('draft_id', $this->request->get['uid']);
107: $this->out('imap_draft', $imap_draft);
108: }
109: return;
110: }
111: Hm_Msgs::add('Could not load the IMAP mailbox.', 'danger');
112: }
113: }
114: }
115:
116: /**
117: * @subpackage smtp/handler
118: */
119: class Hm_Handler_load_smtp_is_imap_forward_as_attachment extends Hm_Handler_Module
120: {
121: public function process() {
122: if (!$this->module_is_supported('imap')) {
123: return;
124: }
125:
126: if (array_key_exists('forward_as_attachment', $this->request->get)) {
127: $path = explode('_', $this->request->get['list_path']);
128: $mailbox = Hm_IMAP_List::get_connected_mailbox($path[1]);
129: if ($mailbox && $mailbox->authed()) {
130: $msg_header = $mailbox->get_message_headers(hex2bin($path[2]), $this->request->get['uid']);
131: if (!array_key_exists('From', $msg_header) || count($msg_header) == 0) {
132: return;
133: }
134: $content = $mailbox->get_message_content(hex2bin($path[2]), $this->request->get['uid']);
135:
136: # Attachment Download
137: $attached_files = [];
138: $this->session->set('uploaded_files', array());
139:
140: $file_dir = $this->config->get('attachment_dir') . DIRECTORY_SEPARATOR . md5($this->session->get('username', false)) . DIRECTORY_SEPARATOR;
141: if (!is_dir($file_dir)) {
142: mkdir($file_dir);
143: }
144: $basename = str_replace(',', '', $msg_header['Subject']);
145: $name = $basename. '.eml';
146: $file_path = $file_dir . $name;
147: $attached_files[$this->request->get['uid']][] = array(
148: 'name' => $name,
149: 'type' => 'message/rfc822',
150: 'size' => strlen($content),
151: 'tmp_name' => $file_path,
152: 'filename' => $file_path,
153: 'basename' => $basename
154: );
155: $content = Hm_Crypt::ciphertext($content, Hm_Request_Key::generate());
156: file_put_contents($file_path, $content);
157: $this->session->set('uploaded_files', $attached_files);
158: $this->out('as_attr', true);
159: }
160: }
161: }
162: }
163:
164: /**
165: * @subpackage smtp/handler
166: */
167: class Hm_Handler_load_smtp_is_imap_forward extends Hm_Handler_Module
168: {
169: public function process() {
170: if (!$this->module_is_supported('imap')) {
171: return;
172: }
173: if (array_key_exists('forward', $this->request->get)) {
174: $path = explode('_', $this->request->get['list_path']);
175: $mailbox = Hm_IMAP_List::get_connected_mailbox($path[1]);
176: if ($mailbox && $mailbox->authed()) {
177: list ($msg_struct, $msg_struct_first, $msg_text, $part) = $mailbox->get_structured_message(hex2bin($path[2]), $this->request->get['uid'], false, true);
178: $msg_header = $mailbox->get_message_headers(hex2bin($path[2]), $this->request->get['uid']);
179: if (!array_key_exists('From', $msg_header) || count($msg_header) == 0) {
180: return;
181: }
182:
183: # Attachment Download
184: $attached_files = [];
185: $this->session->set('uploaded_files', array());
186: if (array_key_exists(0, $msg_struct) && array_key_exists('subs', $msg_struct[0])) {
187: $file_dir = $this->config->get('attachment_dir') . DIRECTORY_SEPARATOR . md5($this->session->get('username', false)) . DIRECTORY_SEPARATOR;
188: if (!is_dir($file_dir)) {
189: mkdir($file_dir);
190: }
191: foreach ($msg_struct[0]['subs'] as $ind => $sub) {
192: if ($ind != '0.1') {
193: $new_attachment['basename'] = $sub['description'];
194: $new_attachment['name'] = $sub['attributes']['name'] ?? $sub['attributes']['filename']; // some file types (i.e. pdf) use the filename attribute instead of name.
195: $new_attachment['size'] = $sub['size'];
196: $new_attachment['type'] = $sub['type'] . "/" . $sub['subtype'];
197: $file_path = $file_dir . $new_attachment['name'];
198: $content = Hm_Crypt::ciphertext($mailbox->get_message_content(hex2bin($path[2]), $this->request->get['uid'], $ind), Hm_Request_Key::generate());
199: file_put_contents($file_path, $content);
200: $new_attachment['tmp_name'] = $file_path;
201: $new_attachment['filename'] = $file_path;
202: $attached_files[$this->request->get['uid']][] = $new_attachment;
203: }
204: }
205: }
206: $this->session->set('uploaded_files', $attached_files);
207: }
208: }
209: }
210: }
211:
212: /**
213: * @subpackage smtp/handler
214: */
215: class Hm_Handler_smtp_default_server extends Hm_Handler_Module {
216: public function process() {
217: list($success, $form) = $this->process_form(array('username', 'password'));
218: if ($success) {
219: default_smtp_server($this->user_config, $this->session, $this->request,
220: $this->config, $form['username'], $form['password']);
221: }
222: }
223: }
224:
225: /**
226: * @subpackage smtp/handler
227: */
228: class Hm_Handler_process_compose_type extends Hm_Handler_Module {
229: public function process() {
230: function smtp_compose_type_callback($val) { return $val; }
231: process_site_setting('smtp_compose_type', $this, 'smtp_compose_type_callback', DEFAULT_SMTP_COMPOSE_TYPE);
232: }
233: }
234:
235: /**
236: * @subpackage smtp/handler
237: */
238: class Hm_Handler_process_auto_bcc extends Hm_Handler_Module {
239: public function process() {
240: function smtp_auto_bcc_callback($val) { return $val; }
241: process_site_setting('smtp_auto_bcc', $this, 'smtp_auto_bcc_callback', DEFAULT_SMTP_AUTO_BCC, true);
242: }
243: }
244:
245: /**
246: * @subpackage smtp/handler
247: */
248: class Hm_Handler_get_test_chunk extends Hm_Handler_Module {
249: public function process() {
250: $filepath = $this->config->get('attachment_dir');
251: $filepath = $filepath.'/chunks-'.$this->request->get['resumableIdentifier'];
252: $chunk_file = $filepath.'/'.$this->request->get['resumableFilename'].'.part'.$this->request->get['resumableChunkNumber'];
253: if (file_exists($chunk_file)) {
254: header("HTTP/1.0 200 Ok");
255: } else {
256: header("HTTP/1.0 404 Not Found");
257: }
258: }
259: }
260:
261: /**
262: * @subpackage smtp/handler
263: */
264: class Hm_Handler_upload_chunk extends Hm_Handler_Module {
265: public function process() {
266: $from = $this->request->get['draft_smtp'];
267: $filepath = $this->config->get('attachment_dir');
268:
269: $userpath = md5($this->session->get('username', false));
270:
271: // create the attachment folder for the profile to avoid
272: if (!is_dir($filepath.'/'.$userpath)) {
273: mkdir($filepath.'/'.$userpath, 0777, true);
274: }
275:
276: if (!empty($this->request->files)) foreach ($this->request->files as $file) {
277: if ($file['error'] != 0) {
278: Hm_Msgs::add('Error '.$file['error'].' in file '.$this->request->get['resumableFilename'], 'danger');
279: continue;
280: }
281:
282: if(isset($this->request->get['resumableIdentifier']) && trim($this->request->get['resumableIdentifier'])!=''){
283: $temp_dir = $filepath.'/'.$userpath.'/chunks-'.$this->request->get['resumableIdentifier'];
284: }
285: $dest_file = $temp_dir.'/'.$this->request->get['resumableFilename'].'.part'.$this->request->get['resumableChunkNumber'];
286:
287: // create the temporary directory
288: if (!is_dir($temp_dir)) {
289: mkdir($temp_dir, 0777, true);
290: }
291:
292: // move the temporary file
293: if (!move_uploaded_file($file['tmp_name'], $dest_file)) {
294: Hm_Msgs::add('Error saving (move_uploaded_file) chunk '.$this->request->get['resumableChunkNumber'].' for file '.$this->request->get['resumableFilename'], 'danger');
295: } else {
296: // check if all the parts present, and create the final destination file
297: $result = createFileFromChunks($temp_dir, $this->request->get['resumableFilename'],
298: $this->request->get['resumableChunkSize'],
299: $this->request->get['resumableTotalSize'],
300: $this->request->get['resumableTotalChunks']);
301: }
302: }
303: }
304: }
305:
306: /**
307: * @subpackage smtp/handler
308: */
309: class Hm_Handler_smtp_save_draft extends Hm_Handler_Module {
310: public function process() {
311: $to = array_key_exists('draft_to', $this->request->post) ? $this->request->post['draft_to'] : '';
312: $body = array_key_exists('draft_body', $this->request->post) ? $this->request->post['draft_body'] : '';
313: $subject = array_key_exists('draft_subject', $this->request->post) ? $this->request->post['draft_subject'] : '';
314: $smtp = array_key_exists('draft_smtp', $this->request->post) ? $this->request->post['draft_smtp'] : '';
315: $cc = array_key_exists('draft_cc', $this->request->post) ? $this->request->post['draft_cc'] : '';
316: $bcc = array_key_exists('draft_bcc', $this->request->post) ? $this->request->post['draft_bcc'] : '';
317: $inreplyto = array_key_exists('draft_in_reply_to', $this->request->post) ? $this->request->post['draft_in_reply_to'] : '';
318: $draft_id = array_key_exists('draft_id', $this->request->post) ? $this->request->post['draft_id'] : false;
319: $draft_notice = array_key_exists('draft_notice', $this->request->post) ? $this->request->post['draft_notice'] : false;
320: $uploaded_files = array_key_exists('uploaded_files', $this->request->post) ? $this->request->post['uploaded_files'] : false;
321: $delivery_receipt = array_key_exists('compose_delivery_receipt', $this->request->post) ? $this->request->post['compose_delivery_receipt'] : false;
322: $schedule = array_key_exists('schedule', $this->request->post) ? $this->request->post['schedule'] : '';
323:
324: if (array_key_exists('delete_uploaded_files', $this->request->post) && $this->request->post['delete_uploaded_files']) {
325: delete_uploaded_files($this->session, $draft_id);
326: return;
327: }
328:
329: $msg_attrs = array('draft_smtp' => $smtp, 'draft_to' => $to, 'draft_body' => $body,
330: 'draft_subject' => $subject, 'draft_cc' => $cc, 'draft_bcc' => $bcc,
331: 'draft_in_reply_to' => $inreplyto);
332: $uploaded_files = !$uploaded_files ? []: explode(',', $uploaded_files);
333: $profiles = $this->get('compose_profiles', array());
334: $profile = profile_from_compose_smtp_id($profiles, $smtp);
335:
336: if ($this->get('save_draft_to_imap') === false) {
337: $from = isset($profile) ? $profile['replyto'] : '';
338: $name = isset($profile) ? $profile['name'] : '';
339: $mime = prepare_draft_mime($msg_attrs, $uploaded_files, $from, $name, $profile['id']);
340: $this->out('draft_mime', $mime);
341: return;
342: }
343:
344: if ($this->module_is_supported('imap')) {
345: $userpath = md5($this->session->get('username', false));
346: foreach($uploaded_files as $key => $file) {
347: $uploaded_files[$key] = $this->config->get('attachment_dir').DIRECTORY_SEPARATOR.$userpath.DIRECTORY_SEPARATOR.$file;
348: }
349: $new_draft_id = save_imap_draft(array('draft_smtp' => $smtp, 'draft_to' => $to, 'draft_body' => $body,
350: 'draft_subject' => $subject, 'draft_cc' => $cc, 'draft_bcc' => $bcc,
351: 'draft_in_reply_to' => $inreplyto, 'delivery_receipt' => $delivery_receipt, 'schedule' => $schedule), $draft_id, $this->session,
352: $this, $this->cache, $uploaded_files, $profile);
353: if ($new_draft_id >= 0) {
354: if ($draft_notice) {
355: $msg = $schedule ? 'Message scheduled to be sent later' : 'Draft saved';
356: Hm_Msgs::add($msg);
357: }
358: $this->out('draft_id', $new_draft_id);
359: }
360: elseif ($draft_notice) {
361: $msg = $schedule ? 'Something went wrong when scheduling draft' : 'Unable to save draft';
362: Hm_Msgs::add($msg, 'danger');
363: }
364: return;
365: }
366: }
367: }
368:
369: /**
370: * @subpackage smtp/handler
371: */
372: class Hm_Handler_load_smtp_servers_from_config extends Hm_Handler_Module {
373: public function process() {
374: Hm_SMTP_List::init($this->user_config, $this->session);
375: if (Hm_SMTP_List::count() == 0 && $this->page == 'compose') {
376: Hm_Msgs::add('You need at least one configured SMTP server to send outbound messages', 'warning');
377: }
378: $draft = array();
379: $draft_id = next_draft_key($this->session);
380: $reply_type = get_reply_type($this->request->get);
381: if ($reply_type == 'forward') {
382: $draft_id = $this->get('compose_draft_id', -1);
383: if ($draft_id >= 0) {
384: $draft = get_draft($draft_id, $this->session);
385: }
386: } elseif (array_key_exists('draft_id', $this->request->get)) {
387: $draft = get_draft($this->request->get['draft_id'], $this->session);
388: $draft_id = $this->request->get['draft_id'];
389: }
390: elseif (array_key_exists('draft_id', $this->request->post)) {
391: $draft = get_draft($this->request->post['draft_id'], $this->session);
392: $draft_id = $this->request->post['draft_id'];
393: }
394: if ($reply_type) {
395: $this->out('reply_type', $reply_type);
396: }
397: if (is_dir($this->config->get('attachment_dir'))) {
398: $this->out('attachment_dir_access', true);
399: } else {
400: $this->out('attachment_dir_access', false);
401: Hm_Msgs::add('Attachment storage unavailable, please contact your site administrator', 'warning');
402: }
403:
404: $this->out('compose_draft', $draft, false);
405: $this->out('compose_draft_id', $draft_id);
406:
407: if ($draft_id <= 0 && array_key_exists('uid', $this->request->get)) {
408: $draft_id = $this->request->get['uid'];
409: }
410:
411: $this->out('uploaded_files', get_uploaded_files($draft_id, $this->session));
412: $settings = $this->user_config;
413: $compose_type = $settings->get('smtp_compose_type_setting', DEFAULT_SMTP_COMPOSE_TYPE);
414: if ($this->get('is_mobile', false)) {
415: $compose_type = 0;
416: }
417: if (is_array($this->get('compose_draft')) && mb_strlen(trim(join('', $this->get('compose_draft')))) == 0 && array_key_exists('compose_to', $this->request->get)) {
418: $draft = array();
419: foreach (parse_mailto($this->request->get['compose_to']) as $name => $val) {
420: if (!$val) {
421: continue;
422: }
423: $draft[$name] = $val;
424: }
425: $this->out('compose_draft', $draft);
426: }
427: $this->out('smtp_compose_type', $compose_type);
428: $this->out('enable_compose_delivery_receipt_setting', $settings->get('enable_compose_delivery_receipt_setting'));
429: }
430: }
431:
432: /**
433: * @subpackage smtp/handler
434: */
435: class Hm_Handler_process_add_smtp_server extends Hm_Handler_Module {
436: public function process() {
437: if (isset($this->request->post['submit_smtp_server'])) {
438: list($success, $form) = $this->process_form(array('new_smtp_name', 'new_smtp_address', 'new_smtp_port'));
439: if (!$success) {
440: Hm_Msgs::add('You must supply a name, a server and a port', 'warning');
441: }
442: else {
443: $tls = false;
444: if (array_key_exists('tls', $this->request->post) && $this->request->post['tls']) {
445: $tls = true;
446: }
447: if ($con = @fsockopen($form['new_smtp_address'], $form['new_smtp_port'], $errno, $errstr, 2)) {
448: Hm_SMTP_List::add(array(
449: 'name' => $form['new_smtp_name'],
450: 'server' => $form['new_smtp_address'],
451: 'port' => $form['new_smtp_port'],
452: 'tls' => $tls));
453:
454: Hm_Msgs::add('Added SMTP server!');
455: $this->session->record_unsaved('SMTP server added');
456: }
457: else {
458: $this->session->set('add_form_vals', $form);
459: Hm_Msgs::add(sprintf('Could not add server: %s', $errstr), 'danger');
460: }
461: }
462: }
463: else {
464: $this->out('add_form_vals', $this->session->get('add_form_vals', array()));
465: $this->session->set('add_form_vals', array());
466: }
467: }
468: }
469:
470: /**
471: * @subpackage smtp/handler
472: */
473: class Hm_Handler_add_smtp_servers_to_page_data extends Hm_Handler_Module {
474: public function process() {
475: $servers = Hm_SMTP_List::dump();
476: $this->out('smtp_servers', $servers);
477: $this->out('compose_drafts', $this->session->get('compose_drafts', array()));
478: }
479: }
480:
481: /**
482: * @subpackage smtp/handler
483: */
484: class Hm_Handler_save_smtp_servers extends Hm_Handler_Module {
485: public function process() {
486: Hm_SMTP_List::save();
487: }
488: }
489:
490: /**
491: * @subpackage smtp/handler
492: */
493: class Hm_Handler_smtp_delete extends Hm_Handler_Module {
494: public function process() {
495: if (isset($this->request->post['smtp_delete'])) {
496: list($success, $form) = $this->process_form(array('smtp_server_id'));
497: if ($success) {
498: $res = Hm_SMTP_List::del($form['smtp_server_id']);
499: if ($res) {
500: $this->out('deleted_server_id', $form['smtp_server_id']);
501: Hm_Msgs::add('Server deleted');
502: }
503: }
504: }
505: }
506: }
507:
508: /**
509: * @subpackage smtp/handler
510: */
511: class Hm_Handler_smtp_connect extends Hm_Handler_Module {
512: public function process() {
513: $smtp = false;
514: if (isset($this->request->post['smtp_connect'])) {
515: list($success, $form) = $this->process_form(array('smtp_server_id'));
516: $smtp_details = Hm_SMTP_List::dump($form['smtp_server_id'], true);
517: if ($success && $smtp_details) {
518: if (array_key_exists('auth', $smtp_details) && $smtp_details['auth'] == 'xoauth2') {
519: $results = smtp_refresh_oauth2_token($smtp_details, $this->config);
520: if (!empty($results)) {
521: if (Hm_SMTP_List::update_oauth2_token($form['smtp_server_id'], $results[1], $results[0])) {
522: Hm_Debug::add(sprintf('Oauth2 token refreshed for SMTP server id %s', $form['smtp_server_id']), 'info');
523: Hm_SMTP_List::save();
524: }
525: }
526: }
527: $mailbox = Hm_SMTP_List::connect($form['smtp_server_id'], false, $smtp_details['user'], $smtp_details['pass']);
528: if ($mailbox && $mailbox->authed()) {
529: Hm_Msgs::add(sprintf("Successfully authenticated to the %s server : %s", $smtp_details['type'], $smtp_details['user']));
530: }
531: elseif ($mailbox && $mailbox->state() == 'connected') {
532: Hm_Msgs::add("Connected, but failed to authenticate to the SMTP server", "warning");
533: }
534: else {
535: Hm_Msgs::add("Failed to authenticate to the SMTP server", "danger");
536: }
537: }
538: }
539: }
540: }
541:
542: /**
543: * @subpackage smtp/handler
544: */
545: class Hm_Handler_profile_status extends Hm_Handler_Module {
546: public function process() {
547: $profiles = $this->user_config->get('profiles');
548: $profile_value = $this->request->post['profile_value'];
549:
550: if (!mb_strstr($profile_value, '.')) {
551: Hm_Msgs::add('Please create a profile for saving sent messages', 'warning');
552: return;
553: }
554: $profile = profile_from_compose_smtp_id($profiles, $profile_value);
555: if (!$profile) {
556: Hm_Msgs::add('Please create a profile for saving sent messages', 'warning');
557: return;
558: }
559: $imap_profile = Hm_IMAP_List::fetch($profile['user'], $profile['server']);
560: $specials = get_special_folders($this, $imap_profile['id']);
561: if ($imap_profile && (!array_key_exists('sent', $specials) || !$specials['sent'])) {
562: Hm_Msgs::add('Please configure a sent folder for account ' . $imap_profile['name'], 'warning');
563: }
564: }
565: }
566:
567: if (!hm_exists('get_mime_type')) {
568: function get_mime_type($filename)
569: {
570: $idx = explode('.', $filename);
571: $count_explode = count($idx);
572: $idx = mb_strtolower($idx[$count_explode - 1]);
573:
574: $mimet = array(
575: 'txt' => 'text/plain',
576: 'htm' => 'text/html',
577: 'html' => 'text/html',
578: 'php' => 'text/html',
579: 'css' => 'text/css',
580: 'js' => 'application/javascript',
581: 'json' => 'application/json',
582: 'xml' => 'application/xml',
583: 'swf' => 'application/x-shockwave-flash',
584: 'flv' => 'video/x-flv',
585:
586: // images
587: 'png' => 'image/png',
588: 'jpe' => 'image/jpeg',
589: 'jpeg' => 'image/jpeg',
590: 'jpg' => 'image/jpeg',
591: 'gif' => 'image/gif',
592: 'bmp' => 'image/bmp',
593: 'ico' => 'image/vnd.microsoft.icon',
594: 'tiff' => 'image/tiff',
595: 'tif' => 'image/tiff',
596: 'svg' => 'image/svg+xml',
597: 'svgz' => 'image/svg+xml',
598:
599: // archives
600: 'zip' => 'application/zip',
601: 'rar' => 'application/x-rar-compressed',
602: 'exe' => 'application/x-msdownload',
603: 'msi' => 'application/x-msdownload',
604: 'cab' => 'application/vnd.ms-cab-compressed',
605:
606: // audio/video
607: 'mp3' => 'audio/mpeg',
608: 'qt' => 'video/quicktime',
609: 'mov' => 'video/quicktime',
610:
611: // adobe
612: 'pdf' => 'application/pdf',
613: 'psd' => 'image/vnd.adobe.photoshop',
614: 'ai' => 'application/postscript',
615: 'eps' => 'application/postscript',
616: 'ps' => 'application/postscript',
617:
618: // ms office
619: 'doc' => 'application/msword',
620: 'rtf' => 'application/rtf',
621: 'xls' => 'application/vnd.ms-excel',
622: 'ppt' => 'application/vnd.ms-powerpoint',
623: 'docx' => 'application/msword',
624: 'xlsx' => 'application/vnd.ms-excel',
625: 'pptx' => 'application/vnd.ms-powerpoint',
626:
627:
628: // open office
629: 'odt' => 'application/vnd.oasis.opendocument.text',
630: 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
631: );
632:
633: if (isset($mimet[$idx])) {
634: return $mimet[$idx];
635: } else {
636: return 'application/octet-stream';
637: }
638: }
639: }
640:
641: /**
642: * @subpackage smtp/handler
643: */
644: class Hm_Handler_process_compose_form_submit extends Hm_Handler_Module {
645: public function process() {
646: /* not sending */
647: if (!array_key_exists('smtp_send', $this->request->post)) {
648: $this->out('enable_attachment_reminder', $this->user_config->get('enable_attachment_reminder_setting', false));
649: return;
650: }
651: if (!array_key_exists('compose_smtp_id', $this->request->post)) {
652: return;
653: }
654:
655: /* missing field */
656: list($success, $form) = $this->process_form(array('compose_to', 'compose_subject', 'compose_body', 'compose_smtp_id', 'draft_id', 'post_archive', 'next_email_post'));
657: if (!$success) {
658: Hm_Msgs::add('Required field missing', 'warning');
659: return;
660: }
661:
662: /* defaults */
663: $smtp_id = server_from_compose_smtp_id($form['compose_smtp_id']);
664: $to = $form['compose_to'];
665: $subject = $form['compose_subject'];
666: $body_type = $this->get('smtp_compose_type', DEFAULT_SMTP_COMPOSE_TYPE);
667: $draft = array(
668: 'draft_to' => $form['compose_to'],
669: 'draft_body' => '',
670: 'draft_subject' => $form['compose_subject'],
671: 'draft_smtp' => $smtp_id
672: );
673: $delivery_receipt = !empty($this->request->post['compose_delivery_receipt']);
674: $from_params = '';
675: $recipients_params = '';
676:
677: /* parse attachments */
678: $uploaded_files = [];
679: if (!empty($this->request->post['send_uploaded_files'])) {
680: $uploaded_files = explode(',', $this->request->post['send_uploaded_files']);
681: foreach($uploaded_files as $key => $file) {
682: $uploaded_files[$key] = $this->config->get('attachment_dir').'/'.md5($this->session->get('username', false)).'/'.$file;
683: }
684: }
685:
686: $uploaded_files = get_uploaded_files_from_array(
687: $uploaded_files
688: );
689:
690: /* msg details */
691: list($body, $cc, $bcc, $in_reply_to, $draft) = get_outbound_msg_detail($this->request->post, $draft, $body_type);
692:
693: /* smtp server details */
694: $smtp_details = Hm_SMTP_List::dump($smtp_id, true);
695: if (!$smtp_details) {
696: Hm_Msgs::add('Could not use the selected SMTP server', 'warning');
697: repopulate_compose_form($draft, $this);
698: return;
699: }
700:
701: /* profile details */
702: $profiles = $this->get('compose_profiles', array());
703: list($imap_server, $from_name, $reply_to, $from) = get_outbound_msg_profile_detail($form, $profiles, $smtp_details, $this);
704:
705: /* xoauth2 check */
706: smtp_refresh_oauth2_token_on_send($smtp_details, $this, $smtp_id);
707:
708: /* adjust from and reply to addresses */
709: list($from, $reply_to) = outbound_address_check($this, $from, $reply_to);
710:
711: /* try to connect */
712: $mailbox = Hm_SMTP_List::connect($smtp_id, false);
713: if (! $mailbox || ! $mailbox->authed()) {
714: Hm_Msgs::add("Failed to authenticate to the SMTP server", "danger");
715: repopulate_compose_form($draft, $this);
716: return;
717: }
718:
719: /* build message */
720: $mime = new Hm_MIME_Msg($to, $subject, $body, $from, $body_type, $cc, $bcc, $in_reply_to, $from_name, $reply_to, $delivery_receipt);
721:
722: /* add attachments */
723: $mime->add_attachments($uploaded_files);
724: $res = $mime->process_attachments();
725:
726: /* get smtp recipients */
727: $recipients = $mime->get_recipient_addresses();
728: if (empty($recipients)) {
729: Hm_Msgs::add("No valid recipients found", "warning");
730: repopulate_compose_form($draft, $this);
731: return;
732: }
733:
734: /* send the message */
735: $err_msg = $mailbox->send_message($from, $recipients, $mime->get_mime_msg(), $this->user_config->get('enable_compose_delivery_receipt_setting', false) && !empty($this->request->post['compose_delivery_receipt']));
736: if ($err_msg) {
737: Hm_Msgs::add(sprintf("%s", $err_msg), 'danger');
738: repopulate_compose_form($draft, $this);
739: return;
740: }
741:
742: /* check for auto-bcc */
743: $auto_bcc = $this->user_config->get('smtp_auto_bcc_setting', DEFAULT_SMTP_AUTO_BCC);
744: if ($auto_bcc) {
745: $mime->set_auto_bcc($from);
746: $bcc_err_msg = $mailbox->send_message($from, array($from), $mime->get_mime_msg());
747: }
748:
749: /* check for associated IMAP server to save a copy */
750: if ($imap_server !== false) {
751: $this->out('save_sent_server', $imap_server, false);
752: $this->out('save_sent_msg', $mime);
753: }
754: else {
755: Hm_Debug::add(sprintf('Unable to save sent message, no IMAP server found for SMTP server: %s', $smtp_details['server']));
756: }
757: if ($this->module_is_supported('contacts') && $this->user_config->get('contact_auto_collect_setting', false)) {
758: $this->out('collect_contacts', true);
759: }
760:
761: // Archive replied message
762: if ($form['post_archive']) {
763: $msg_path = explode('_', $this->request->post['compose_msg_path']);
764: $msg_uid = $this->request->post['compose_msg_uid'];
765:
766: $mailbox = Hm_IMAP_List::get_connected_mailbox($msg_path[1]);
767: if ($mailbox && $mailbox->authed()) {
768: $specials = get_special_folders($this, $msg_path[1]);
769: if (array_key_exists('archive', $specials) && $specials['archive']) {
770: $archive_folder = $specials['archive'];
771: $mailbox->message_action(hex2bin($msg_path[2]), 'ARCHIVE', array($msg_uid));
772: $mailbox->message_action(hex2bin($msg_path[2]), 'MOVE', array($msg_uid), $archive_folder);
773: }
774: }
775: }
776:
777: if ($form['next_email_post']) {
778: $this->out('msg_next_link', $form['next_email_post']);
779: }
780:
781: /* clean up */
782: $this->out('msg_sent', true);
783: Hm_Msgs::add("Message Sent");
784:
785: /* if it is a draft, remove it */
786: if ($this->module_is_supported('imap') && $imap_server !== false && $form['draft_id'] > 0) {
787: $specials = get_special_folders($this, $imap_server);
788: delete_draft($form['draft_id'], $this->cache, $imap_server, $specials['draft']);
789: }
790:
791: delete_uploaded_files($this->session, $form['draft_id']);
792: if ($form['draft_id'] > 0) {
793: delete_uploaded_files($this->session, 0);
794: }
795: }
796: }
797:
798: /**
799: * Determine if composer_from is set
800: * @subpackage smtp/handler
801: */
802: class Hm_Handler_smtp_from_replace extends Hm_Handler_Module {
803: public function process()
804: {
805: if (array_key_exists('compose_from', $this->request->get)) {
806: $this->out('compose_from', $this->request->get['compose_from']);
807: }
808: }
809: }
810:
811: /**
812: * Determine if composer_from is set
813: * @subpackage smtp/handler
814: */
815: class Hm_Handler_smtp_subject_replace extends Hm_Handler_Module {
816: public function process()
817: {
818: if (array_key_exists('compose_subject', $this->request->get)) {
819: $this->out('compose_subject', $this->request->get['compose_subject']);
820: }
821: }
822: }
823:
824: /**
825: * Determine if auto-bcc is active
826: * @subpackage smtp/handler
827: */
828: class Hm_Handler_smtp_auto_bcc_check extends Hm_Handler_Module {
829: /**
830: * Set the auto bcc state for output modules to use
831: */
832: public function process() {
833: $this->out('auto_bcc_enabled', $this->user_config->get('smtp_auto_bcc_setting', DEFAULT_SMTP_AUTO_BCC));
834: }
835: }
836:
837: class Hm_Handler_process_enable_attachment_reminder_setting extends Hm_Handler_Module {
838: public function process() {
839: function enable_attachment_reminder_callback($val) { return $val; }
840: process_site_setting('enable_attachment_reminder', $this, 'enable_attachment_reminder_callback', false, true);
841: }
842: }
843:
844: /**
845: * @subpackage smtp/handler
846: */
847: class Hm_Handler_attachment_dir extends Hm_Handler_Module {
848: public function process() {
849: $this->out('attachment_dir', $this->config->get('attachment_dir'));
850: }
851: }
852:
853: /**
854: * @subpackage smtp/handler
855: */
856: class Hm_Handler_clear_attachment_chunks extends Hm_Handler_Module {
857: public function process() {
858: $attachment_dir = $this->config->get('attachment_dir');
859: $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($attachment_dir));
860: foreach ($rii as $file) {
861: if ($file->getFilename() == '.' || $file->getFilename() == '..') {
862: continue;
863: }
864: if (is_dir($file->getPath()) && $file->getPath() != $attachment_dir){
865: if (mb_strpos($file->getPath(), 'chunks-') !== False) {
866: rrmdir($file->getPath());
867: }
868: }
869: }
870: Hm_Msgs::add('Attachment chunks cleaned');
871: }
872: }
873:
874: /**
875: * @subpackage keyboard_shortcuts/handler
876: */
877: class Hm_Handler_process_enable_compose_delivery_receipt_setting extends Hm_Handler_Module {
878: public function process() {
879: function compose_delivery_receipt_enabled_callback($val) { return $val; }
880: process_site_setting('enable_compose_delivery_receipt', $this, 'compose_delivery_receipt_enabled_callback', false, true);
881: }
882: }
883:
884: class Hm_Output_enable_compose_delivery_receipt_setting extends Hm_Output_Module {
885: protected function output() {
886: $settings = $this->get('user_settings');
887: if (array_key_exists('enable_compose_delivery_receipt', $settings) && $settings['enable_compose_delivery_receipt']) {
888: $checked = ' checked="checked"';
889: $reset = '<span class="tooltip_restore" restore_aria_label="Restore default value"><i class="bi bi-arrow-counterclockwise refresh_list reset_default_value_checkbox"></i></span>';
890: }
891: else {
892: $checked = '';
893: $reset = '';
894: }
895: return '<tr class="general_setting"><td><label class="form-check-label" for="enable_compose_delivery_receipt">'.
896: $this->trans('Enable delivery receipt').'</label></td>'.
897: '<td><input class="form-check-input" type="checkbox" '.$checked.
898: ' value="1" id="enable_compose_delivery_receipt" name="enable_compose_delivery_receipt" />'.$reset.'</td></tr>';
899: }
900: }
901:
902: /**
903: * @subpackage keyboard_shortcuts/output
904: */
905: class Hm_Output_attachment_setting extends Hm_Output_Module {
906: protected function output() {
907: $size_in_kbs = 0;
908: $num_chunks = 0;
909: if (!is_dir($this->get('attachment_dir'))) {
910: return;
911: }
912: $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->get('attachment_dir')));
913: $files = array();
914:
915: foreach ($rii as $file) {
916: if ($file->getFilename() == '.' || $file->getFilename() == '..') {
917: continue;
918: }
919: if ($file->isDir()){
920: continue;
921: }
922: if (mb_strpos($file->getPathname(), '.part') !== False) {
923: $num_chunks++;
924: $size_in_kbs += filesize($file->getPathname());
925: $files[] = $file->getPathname();
926: }
927: }
928: if ($size_in_kbs > 0) {
929: $size_in_kbs = round(($size_in_kbs / 1024), 2);
930: }
931: return '<tr class="general_setting"><td><label>'.
932: $this->trans('Attachment Chunks').'</label></td>'.
933: '<td><small>('.$num_chunks.' Chunks) '.$size_in_kbs.' KB</small> <button id="clear_chunks_button" class="btn btn-light btn-sm border">Clear Chunks</button></td></tr>';
934: }
935: }
936:
937: /**
938: * @subpackage smtp/output
939: */
940: class Hm_Output_enable_attachment_reminder_setting extends Hm_Output_Module {
941: protected function output() {
942: $settings = $this->get('user_settings');
943: if (array_key_exists('enable_attachment_reminder', $settings) && $settings['enable_attachment_reminder']) {
944: $checked = ' checked="checked"';
945: if(!$settings['enable_attachment_reminder']) {
946: $reset = '<span class="tooltip_restore" restore_aria_label="Restore default value"><i class="bi bi-arrow-counterclockwise refresh_list reset_default_value_checkbox"></i></span>';
947: }
948: else {
949: $reset='';
950: }
951: }
952: else {
953: $checked = '';
954: $reset='';
955: }
956: return '<tr class="general_setting"><td><label class="form-check-label" for="enable_attachment_reminder">'.
957: $this->trans('Enable Attachment Reminder').'</label></td>'.
958: '<td><input type="checkbox" '.$checked.
959: ' value="1" id="enable_attachment_reminder" class="form-check-input" name="enable_attachment_reminder" data-default-value="false" />'.$reset.'</td></tr>';
960: }
961: }
962:
963: /**
964: * @subpackage smtp/output
965: */
966: class Hm_Output_sent_folder_link extends Hm_Output_Module {
967: protected function output() {
968: $res = '<li class="menu_sent"><a class="unread_link" href="?page=message_list&amp;list_path=sent">';
969: if (!$this->get('hide_folder_icons')) {
970: $res .= '<i class="bi bi-send-check-fill menu-icon"></i>';
971: }
972: $res .= '<span class="nav-label">'.$this->trans('Sent').'</span></a></li>';
973: $this->concat('formatted_folder_list', $res);
974: }
975: }
976:
977: /**
978: * @subpackage smtp/output
979: */
980: class Hm_Output_compose_title extends Hm_Output_Module {
981: protected function output() {
982: return'<div class="content_title px-3">'.$this->trans('Compose').'</div>';
983: }
984: }
985:
986: /**
987: * @subpackage smtp/output
988: */
989: class Hm_Output_compose_form_start extends Hm_Output_Module {
990: protected function output() {
991: $res = '<div class="container">';
992: $res .= '<div class="row justify-content-md-center">';
993: $res .= '<div class="col col-lg-10 col-xl-8">';
994: $res .= '<form class="compose_form p-4" method="post" action="?page=compose" data-reminder="' . $this->get('enable_attachment_reminder', 0) . '">';
995: return $res;
996: }
997: }
998:
999: /**
1000: * @subpackage smtp/output
1001: */
1002: class Hm_Output_compose_form_end extends Hm_Output_Module {
1003: protected function output() {
1004: return '</form></div></div></div>';
1005: }
1006: }
1007:
1008: /**
1009: * @subpackage smtp/output
1010: */
1011: class Hm_Output_compose_form_attach extends Hm_Output_Module {
1012: protected function output() {
1013: return '<form enctype="multipart/form-data" class="compose_attach_form">'.
1014: '<input class="compose_attach_file" type="file" name="compose_attach_file" />'.
1015: '<input type="hidden" name="compose_attach_page_id" value="ajax_smtp_attach_file" />'.
1016: '</form>';
1017: }
1018: }
1019:
1020: /**
1021: * @subpackage smtp/output
1022: */
1023: class Hm_Output_compose_form_draft_list extends Hm_Output_Module {
1024: protected function output() {
1025: $drafts = $this->get('compose_drafts', array());
1026: if (!count($drafts)) {
1027: return;
1028: }
1029: $res = '<i class="bi bi-pencil-square draft_title refresh_list" title="'.$this->trans('Drafts').'"></i>';
1030: $res .= '<div class="draft_list">';
1031: foreach ($drafts as $id => $draft) {
1032: $subject = trim($draft['draft_subject']) ? trim($draft['draft_subject']) : 'Draft '.($id+1);
1033: $res .= '<div class="draft_'.$this->html_safe($id).'"><a class="draft_link" href="?page=compose&draft_id='.
1034: $this->html_safe($id).'">'.$this->html_safe($subject).'</a> '.
1035: '<i class="bi bi-x-circle-fill delete_draft" data-id="'.$this->html_safe($id).'"></i></div>';
1036: }
1037: $res .= '</div>';
1038: return $res;
1039: }
1040: }
1041: /**
1042: * @subpackage smtp/output
1043: */
1044: class Hm_Output_compose_form_content extends Hm_Output_Module {
1045: protected function output() {
1046: $to = '';
1047: $body = '';
1048: $files = $this->get('uploaded_files', array());
1049: $cc = '';
1050: $bcc = '';
1051: $in_reply_to = '';
1052: $recip = '';
1053:
1054: $draft = $this->get('compose_draft', array());
1055: $reply = $this->get('reply_details', array());
1056: $imap_draft = $this->get('imap_draft', array());
1057: $reply_type = $this->get('reply_type', '');
1058: $html = $this->get('smtp_compose_type', DEFAULT_SMTP_COMPOSE_TYPE);
1059: $msg_path = $this->get('list_path', '');
1060: $msg_uid = $this->get('uid', '');
1061: $from = $this->get('compose_from');
1062: $subject = $this->get('compose_subject');
1063: $forward_as_attachment=$this->get('as_attr');
1064:
1065: if (!$msg_path) {
1066: $msg_path = $this->get('compose_msg_path', '');
1067: }
1068: if (!$msg_uid) {
1069: $msg_uid = $this->get('compose_msg_uid', '');
1070: }
1071: $smtp_id = false;
1072: $draft_id = $this->get('compose_draft_id', 0);
1073:
1074: if (!empty($reply)) {
1075: list($to, $cc, $subject, $body, $in_reply_to) = format_reply_fields(
1076: $reply['msg_text'], $reply['msg_headers'], $reply['msg_struct'], $html, $this, $reply_type);
1077:
1078: $recip = get_primary_recipient($this->get('compose_profiles', array()), $reply['msg_headers'],
1079: $this->get('smtp_servers', array()));
1080: }
1081:
1082: if(!empty($imap_draft)) {
1083: $recip = get_primary_recipient($this->get('compose_profiles', array()), $imap_draft,
1084: $this->get('smtp_servers', array(), True));
1085: }
1086:
1087: if (!empty($draft)) {
1088: if (array_key_exists('draft_to', $draft)) {
1089: $to = $draft['draft_to'];
1090: }
1091: if (array_key_exists('draft_subject', $draft)) {
1092: $subject = $draft['draft_subject'];
1093: }
1094: if (array_key_exists('draft_body', $draft)) {
1095: $body= $draft['draft_body'];
1096: }
1097: if (array_key_exists('draft_smtp', $draft)) {
1098: $smtp_id = $draft['draft_smtp'];
1099: }
1100: if (array_key_exists('draft_in_reply_to', $draft)) {
1101: $in_reply_to = $draft['draft_in_reply_to'];
1102: }
1103: if (array_key_exists('draft_cc', $draft)) {
1104: $cc = $draft['draft_cc'];
1105: }
1106: if (array_key_exists('draft_bcc', $draft)) {
1107: $bcc = $draft['draft_bcc'];
1108: }
1109: }
1110: if(isset($forward_as_attachment)){
1111: $body="";
1112: $to="";
1113: $subject ="";
1114: $cc="";
1115: $from="";
1116: }
1117: if ($imap_draft) {
1118: if (array_key_exists('Body', $imap_draft)) {
1119: $body = $imap_draft['Body'];
1120: }
1121: if (array_key_exists('To', $imap_draft)) {
1122: $to = $imap_draft['To'];
1123: }
1124: if (array_key_exists('Subject', $imap_draft)) {
1125: $subject = $imap_draft['Subject'];
1126: }
1127: if (array_key_exists('Cc', $imap_draft)) {
1128: $cc = $imap_draft['Cc'];
1129: }
1130: if (array_key_exists('From', $imap_draft)) {
1131: $from = $imap_draft['From'];
1132: }
1133: $draft_id = $msg_uid;
1134: }
1135:
1136: // User clicked on compose
1137: if ($reply_type) {
1138: $imap_server_id = explode('_', $msg_path)[1];
1139: $imap_server = Hm_IMAP_List::get($imap_server_id, false);
1140: $reply_from = process_address_fld($reply['msg_headers']['From']);
1141:
1142: if ($reply_type == 'reply_all' && $reply_from[0]['email'] != $imap_server['user'] && mb_strpos($to, $reply_from[0]['email']) === false) {
1143: $to .= ', '.$reply_from[0]['label'].' '.$reply_from[0]['email'];
1144: }
1145: }
1146:
1147: $send_disabled = '';
1148: if (count($this->get('smtp_servers', array())) == 0) {
1149: $send_disabled = 'disabled="disabled" ';
1150: }
1151: $res = '';
1152: if ($html == 1) {
1153: // TODO: The client should be provided all relevant configs so it can tell what appropriate js code to execute. This should not be handled by backend modules.
1154: $res .= '<script type="text/javascript">window.HTMLEditor = true</script>';
1155: }
1156:
1157: $res .= '<input type="hidden" name="hm_page_key" value="'.$this->html_safe(Hm_Request_Key::generate()).'" />'.
1158: '<input type="hidden" name="compose_msg_path" value="'.$this->html_safe($msg_path).'" />'.
1159: '<input type="hidden" name="post_archive" class="compose_post_archive" value="0" />'.
1160: '<input type="hidden" name="next_email_post" class="compose_next_email_data" value="" />'.
1161: '<input type="hidden" name="compose_msg_uid" value="'.$this->html_safe($msg_uid).'" />'.
1162: '<input type="hidden" class="compose_draft_id" name="draft_id" value="'.$this->html_safe($draft_id).'" />'.
1163: '<input type="hidden" class="saving_draft" value="0" />'.
1164: '<input type="hidden" class="compose_in_reply_to" name="compose_in_reply_to" value="'.$this->html_safe($in_reply_to).'" />'.
1165:
1166: '<div class="to_outer">'.
1167: '<div class="mb-3 position-relative compose_container p-1 w-100 form-control">'.
1168: '<div class="bubbles bubble_dropdown"></div>'.
1169: '<input autocomplete="off" value="'.$this->html_safe($to).'" required name="compose_to" class="compose_to w-75" type="text" placeholder="'.$this->trans('To').'" id="compose_to" />'.
1170: '<a href="#" tabindex="-1" class="toggle_recipients position-absolute end-0 pe-2"><i class="bi bi-plus-square-fill fs-3"></i></a>'.
1171: '<div id="to_contacts"></div>'.
1172: '</div>'.
1173: '</div>'.
1174:
1175: '<div class="recipient_fields">'.
1176: '<div class="mb-3 compose_container form-control">'.
1177: '<div class="bubbles bubble_dropdown"></div>'.
1178: '<input autocomplete="off" value="'.$this->html_safe($cc).'" name="compose_cc" class="compose_cc" type="text" placeholder="'.$this->trans('Cc').'" id="compose_cc" />'.
1179: '</div>'.
1180: '<div id="cc_contacts"></div>'.
1181: '<div class="mb-3 compose_container form-control">'.
1182: '<div class="bubbles bubble_dropdown"></div>'.
1183: '<input autocomplete="off" value="'.$this->html_safe($bcc).'" name="compose_bcc" class="compose_bcc" type="text" placeholder="'.$this->trans('Bcc').'" id="compose_bcc" />'.
1184: '</div>'.
1185: '<div id="bcc_contacts"></div>'.
1186: '</div>'.
1187: '<div class="form-floating mb-3">'.
1188: '<input value="'.$this->html_safe($subject).'" name="compose_subject" class="compose_subject form-control" type="text" placeholder="'.$this->trans('Subject').'" id="compose_subject" />'.
1189: '<label for="compose_subject">'.$this->trans('Subject').'</label>'.
1190: '</div>'.
1191: '<div class="form-floating mb-3">'.
1192: '<textarea id="compose_body" name="compose_body" class="compose_body form-control" placeholder="'.$this->trans('Message').'">'.$this->html_safe($body).'</textarea>'.
1193: (!$html ? '<label for="compose_body">'.$this->trans('Message').'</label>': '').
1194: '</div>';
1195: if($this->get('enable_compose_delivery_receipt_setting')) {
1196: $res .= '<div class="form-check mb-3"><input value="1" name="compose_delivery_receipt" id="compose_delivery_receipt" type="checkbox" class="form-check-input" checked/><label for="compose_delivery_receipt" class="form-check-label">'.$this->trans('Request a delivery receipt').'</label></div>';
1197: }
1198: if ($html == 2) {
1199: $res .= '<link href="'.WEB_ROOT.'modules/smtp/assets/markdown/editor.css" rel="stylesheet" />'.
1200: '<script type="text/javascript" src="'.WEB_ROOT.'modules/smtp/assets/markdown/editor.js"></script>'.
1201: '<script type="text/javascript" src="'.WEB_ROOT.'modules/smtp/assets/markdown/marked.js"></script>'.
1202: '<script type="text/javascript">window.mdEditor = new Editor(); mdEditor.render();</script>';
1203: }
1204: $res .= '<table class="uploaded_files">';
1205:
1206: foreach ($files as $file) {
1207: $res .= format_attachment_row($file, $this);
1208: }
1209:
1210: /* select the correct account to unsubscribe from mailing lists */
1211: $selected_id = false;
1212: if (empty($recip) && !empty($from)) {
1213: /* This solves the problem when a profile is not associated with the email */
1214: $server_found = false;
1215: foreach ($this->module_output()['compose_profiles'] as $id => $server) {
1216: if ($server['address'] == $from) {
1217: $server_found = true;
1218: $smtp_profiles = profiles_by_smtp_id($this->get('compose_profiles'), $server['smtp_id']);
1219: foreach ($smtp_profiles as $index => $smtp_profile) {
1220: if ($server == $smtp_profile) {
1221: $selected_id = $server['smtp_id'] . '.' . ($index + 1);
1222: break 2;
1223: }
1224: }
1225: }
1226: }
1227: if (!$server_found) {
1228: foreach ($this->module_output()['smtp_servers'] as $id => $server) {
1229: if ($server['user'] == $from) {
1230: $selected_id = $id;
1231: }
1232: }
1233: $recip = null;
1234: }
1235: }
1236:
1237: // replying a message takes the original imap server and tries to find a profile
1238: // matching that server to preselect on the list of available smtp options
1239: // relying on recipient here might fail as real recipient is sometimes different
1240: // than the address specified in the profile
1241: if (! empty($reply) && $imap_server) {
1242: foreach ($this->get('compose_profiles') as $profile) {
1243: if ($profile['server'] == $imap_server['server'] && $profile['user'] == $imap_server['user']) {
1244: $smtp_profiles = profiles_by_smtp_id($this->get('compose_profiles'), $profile['smtp_id']);
1245: foreach ($smtp_profiles as $index => $smtp_profile) {
1246: if ($profile == $smtp_profile) {
1247: $selected_id = $profile['smtp_id'] . '.' . ($index + 1);
1248: break 2;
1249: }
1250: }
1251: }
1252: }
1253: }
1254:
1255: $res .= '</table>'.
1256: smtp_server_dropdown($this->module_output(), $this, $recip, $selected_id).
1257: '<div class="btn-group dropup">
1258: <button class="smtp_send_placeholder btn btn-primary mt-3" type="button" '.$send_disabled.'>'.$this->trans('Send').'</button><input class="smtp_send d-none" type="submit" value="'.$this->trans('Send').'" name="smtp_send"/>
1259: <button type="button" class="smtp_schedule_send btn btn-primary mt-3 dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false" '.$send_disabled.'>
1260: <span class="visually-hidden">Toggle Dropdown</span>
1261: </button>'.
1262: schedule_dropdown($this).
1263: '</div>';
1264:
1265: if ($this->get('list_path') && ($reply_type == 'reply' || $reply_type == 'reply_all')) {
1266: $res .= '<input class="smtp_send_archive btn btn-primary mt-3" type="button" value="'.$this->trans('Send & Archive').'" name="smtp_send" '.$send_disabled.'/>';
1267: }
1268:
1269: $disabled_attachment = $this->get('attachment_dir_access') ? '' : 'disabled="disabled"';
1270: $res .= '<input type="hidden" value="" id="send_uploaded_files" name="send_uploaded_files" />'.
1271: '<input class="smtp_save btn btn-light float-end mt-3 border" type="button" value="'.$this->trans('Save').'" />'.
1272: '<input class="smtp_reset btn btn-light float-end mt-3 me-2 border" type="button" value="'.$this->trans('Reset').'" />'.
1273: '<input class="compose_attach_button btn btn-light float-end mt-3 me-2 border" value="'.$this->trans('Attach').'" name="compose_attach_button" type="button" '.$disabled_attachment.' />';
1274: return $res;
1275: }
1276: }
1277:
1278: /**
1279: * @subpackage smtp/output
1280: */
1281: class Hm_Output_add_smtp_server_dialog extends Hm_Output_Module {
1282: protected function output() {
1283: if ($this->get('single_server_mode')) {
1284: return '';
1285: }
1286: $count = count(array_filter($this->get('smtp_servers', array()), fn($s) => ($s['type'] ?? null) !== 'ews'));
1287: $count = sprintf($this->trans('%d configured'), $count);
1288: $name = '';
1289: $address = '';
1290: $port = 465;
1291: $add_form_vals = $this->get('add_form_vals', array());
1292: if (array_key_exists('new_smtp_name', $add_form_vals)) {
1293: $name = $this->html_safe($add_form_vals['new_smtp_name']);
1294: }
1295: if (array_key_exists('new_smtp_address', $add_form_vals)) {
1296: $address = $this->html_safe($add_form_vals['new_smtp_address']);
1297: }
1298: if (array_key_exists('new_smtp_port', $add_form_vals)) {
1299: $port = $this->html_safe($add_form_vals['new_smtp_port']);
1300: }
1301:
1302: return '<div class="smtp_server_setup">
1303: <div data-target=".smtp_section" class="server_section border-bottom cursor-pointer px-1 py-3 pe-auto">
1304: <a href="#" class="pe-auto">
1305: <i class="bi bi-file-earmark-text-fill me-3"></i>
1306: <b>'.$this->trans('SMTP Servers').'</b>
1307: </a>
1308: <div class="server_count">'.$count.'</div>
1309: </div>
1310: <div class="smtp_section px-4 pt-3">
1311: <div class="row">
1312: <div class="col-12 col-lg-4 mb-4">
1313: <form class="" method="POST">
1314: <input type="hidden" name="hm_page_key" value="'.$this->html_safe(Hm_Request_Key::generate()).'" />
1315: <div class="subtitle">'.$this->trans('Add an SMTP Server').'</div>
1316:
1317: <div class="form-floating mb-3">
1318: <input required type="text" class="form-control" id="new_smtp_name" name="new_smtp_name" placeholder="'.$this->trans('Account name').'" value="'.$name.'">
1319: <label for="new_smtp_name">'.$this->trans('SMTP account name').'</label>
1320: </div>
1321:
1322: <div class="form-floating mb-3">
1323: <input required type="text" class="form-control" id="new_smtp_address" name="new_smtp_address" placeholder="'.$this->trans('SMTP server address').'" value="'.$address.'">
1324: <label for="new_smtp_address">'.$this->trans('SMTP server address').'</label>
1325: </div>
1326:
1327: <div class="form-floating mb-3">
1328: <input required type="number" class="form-control" id="new_smtp_port" name="new_smtp_port" placeholder="'.$this->trans('Port').'" value="'.$port.'">
1329: <label for="new_smtp_port">'.$this->trans('SMTP port').'</label>
1330: </div>
1331:
1332: <div class="mb-3">
1333: <input type="radio" name="tls" value="1" id="smtp_tls" checked="checked" />
1334: <label for="smtp_tls">'.$this->trans('Use TLS').'</label>
1335: <br />
1336: <input type="radio" name="tls" id="smtp_notls" value="0" />
1337: <label for="smtp_notls">'.$this->trans('STARTTLS or unencrypted').'</label>
1338: </div>
1339:
1340: <div class="">
1341: <input class="btn btn-primary px-5" type="submit" value="'.$this->trans('Add').'" name="submit_smtp_server" />
1342: </div>
1343: </form>
1344: </div>';
1345:
1346: }
1347: }
1348:
1349: /**
1350: * @subpackage smtp/output
1351: */
1352: class Hm_Output_compose_type_setting extends Hm_Output_Module {
1353: protected function output() {
1354: $selected = DEFAULT_SMTP_COMPOSE_TYPE;
1355: $settings = $this->get('user_settings', array());
1356: $reset = '';
1357: if (array_key_exists('smtp_compose_type', $settings)) {
1358: $selected = $settings['smtp_compose_type'];
1359: }
1360: $res = '<tr class="general_setting"><td>'.$this->trans('Outbound mail format').'</td><td><select class="form-select form-select-sm w-auto" name="smtp_compose_type" data-default-value="'.DEFAULT_SMTP_COMPOSE_TYPE.'">';
1361: $res .= '<option ';
1362: if ($selected == 0) {
1363: $res .= 'selected="selected" ';
1364: }
1365: $res .= 'value="0">'.$this->trans('Plain text').'</option><option ';
1366: if ($selected == 1) {
1367: $res .= 'selected="selected" ';
1368: }
1369: $res .= 'value="1">'.$this->trans('HTML').'</option><option ';
1370: if ($selected == 2) {
1371: $res .= 'selected="selected" ';
1372: }
1373: if ($selected != 0) {
1374: $reset = '<span class="tooltip_restore" restore_aria_label="Restore default value"><i class="bi bi-arrow-counterclockwise refresh_list reset_default_value_select"></i></span>';
1375: }
1376: $res .= 'value="2">'.$this->trans('Markdown').'</option></select>'.$reset.'</td></tr>';
1377: return $res;
1378: }
1379: }
1380:
1381: /**
1382: * @subpackage smtp/output
1383: */
1384: class Hm_Output_auto_bcc_setting extends Hm_Output_Module {
1385: protected function output() {
1386: $auto = DEFAULT_SMTP_AUTO_BCC;
1387: $settings = $this->get('user_settings', array());
1388: if (array_key_exists('smtp_auto_bcc', $settings)) {
1389: $auto = $settings['smtp_auto_bcc'];
1390: }
1391: $res = '<tr class="general_setting"><td><label class="form-check-label" for="smtp_auto_bcc">'.$this->trans('Always BCC sending address').'</label></td><td><input class="form-check-input" value="1" type="checkbox" name="smtp_auto_bcc" id="smtp_auto_bcc" data-default-value="false"';
1392: $reset = '';
1393: if ($auto) {
1394: $res .= ' checked="checked"';
1395: $reset = '<span class="tooltip_restore" restore_aria_label="Restore default value"><i class="bi bi-arrow-counterclockwise refresh_list reset_default_value_checkbox"></i></span>';
1396: }
1397: $res .= '>'.$reset.'</td></tr>';
1398: return $res;
1399: }
1400: }
1401:
1402: /**
1403: * @subpackage smtp/output
1404: */
1405: class Hm_Output_filter_upload_file_details extends Hm_Output_Module {
1406: protected function output() {
1407: $file = $this->get('upload_file_details', array());
1408: if (!empty($file)) {
1409: $this->out('file_details', format_attachment_row($file, $this));
1410: }
1411: }
1412: }
1413:
1414: /**
1415: * @subpackage smtp/output
1416: */
1417: class Hm_Output_display_configured_smtp_servers extends Hm_Output_Module {
1418: protected function output() {
1419: if ($this->get('single_server_mode')) {
1420: return '';
1421: }
1422:
1423: $list = $this->get('smtp_servers', array());
1424:
1425: if (empty($list)) {
1426: return '';
1427: }
1428:
1429: $res = '<div class="subtitle mt-4 fw-bold border-top pt-4">'.$this->trans('SMTP Servers').'</div>';
1430: foreach ($list as $index => $vals) {
1431:
1432: $no_edit = false;
1433:
1434: if (array_key_exists('type', $vals) && $vals['type'] == 'ews') {
1435: continue;
1436: }
1437:
1438: if (array_key_exists('user', $vals) && !array_key_exists('nopass', $vals)) {
1439: $disabled = 'disabled="disabled"';
1440: $user_pc = $vals['user'];
1441: $pass_pc = $this->trans('[saved]');
1442: $pass_value = '************';
1443: }
1444: elseif (array_key_exists('user', $vals) && array_key_exists('nopass', $vals)) {
1445: $user_pc = $vals['user'];
1446: $pass_pc = $this->trans('Password');
1447: $disabled = '';
1448: $pass_value = '';
1449: }
1450: else {
1451: $user_pc = '';
1452: $pass_pc = $this->trans('Password');
1453: $disabled = '';
1454: $pass_value = '';
1455: }
1456: $res .= '<div class="smtp_server mb-3">';
1457:
1458: $res .= '<form class="smtp_connect" method="POST"><div class="row">';
1459: $res .= '<input type="hidden" name="hm_page_key" value="'.$this->html_safe(Hm_Request_Key::generate()).'" />';
1460: $res .= '<input type="hidden" name="smtp_server_id" class="smtp_server_id" value="'.$this->html_safe($index).'" />';
1461: $res .= '<div class="row m-0 p-0 credentials-container"><div class="col-lg-2 col-md-6 mb-2 overflow-auto">';
1462: $res .= sprintf('<div class="text-muted"><strong>%s</strong></div>
1463: <div class="server_subtitle">%s/%d %s</div>',
1464: $this->html_safe($vals['name']), $this->html_safe($vals['server']), $this->html_safe($vals['port']), $vals['tls'] ? 'TLS' : '' );
1465: $res .= '</div><div class="col-xl-7 col-lg-7 col-md-9"><div class="row"><div class="col-md-6 col-lg-4">';
1466:
1467: // SMTP Username
1468: $res .= '<div class="form-floating mb-2">';
1469: $res .= '<input '.$disabled.' class="form-control credentials" id="smtp_user_'.$index.'" type="text" name="smtp_user" value="'.$this->html_safe($user_pc).'" placeholder="'.$this->trans('Username').'">';
1470: $res .= '<label for="smtp_user_'.$index.'">'.$this->trans('SMTP username').'</label></div>';
1471: $res .= '</div><div class="col-md-6 col-lg-4">';
1472:
1473: // SMTP Password
1474: $res .= '<div class="form-floating mb-2">';
1475: $res .= '<input '.$disabled.' class="form-control credentials smtp_password" type="password" id="smtp_pass_'.$index.'" name="smtp_pass" value="'.$pass_value.'" placeholder="'.$pass_pc.'">';
1476: $res .= '<label for="smtp_pass_'.$index.'">'.$this->trans('SMTP password').'</label></div>';
1477: $res .= '</div><div class="col-md-6 col-lg-4"></div>';
1478:
1479: // Buttons
1480: $res .= '</div> </div> <div class="col-lg-6 col-xl-3 col-mg-6 d-flex justify-content-start align-items-center">';
1481: if (!$no_edit) {
1482: if (!isset($vals['user']) || !$vals['user']) {
1483: $res .= '<input type="submit" value="'.$this->trans('Delete').'" class="delete_smtp_connection btn btn-light border btn-sm me-2" />';
1484: }
1485: else {
1486: $keysToRemove = array('object', 'connected');
1487: $serverDetails = array_diff_key($vals, array_flip($keysToRemove));
1488:
1489: $res .= '<input type="submit" value="'.$this->trans('Edit').'" class="edit_server_connection btn btn-outline-success btn-sm me-2" data-server-details=\''.$this->html_safe(json_encode($serverDetails)).'\' data-id="'.$this->html_safe($serverDetails['name']).'" data-type="smtp" />';
1490: $res .= '<input type="submit" value="'.$this->trans('Test').'" class="test_smtp_connect btn btn-outline-primary btn-sm me-2" />';
1491: $res .= '<input type="submit" value="'.$this->trans('Delete').'" class="delete_smtp_connection btn btn-outline-danger btn-sm me-2" />';
1492: }
1493: $res .= '<input type="hidden" value="ajax_smtp_debug" name="hm_ajax_hook" />';
1494: }
1495: $res .= '</div></div> </div> </form> </div>';
1496: }
1497: return $res;
1498: }
1499: }
1500:
1501: /**
1502: * @subpackage smtp/output
1503: */
1504: class Hm_Output_compose_page_link extends Hm_Output_Module {
1505: protected function output() {
1506: $res = '<li class="menu_compose"><a class="unread_link" href="?page=compose">';
1507: if (!$this->get('hide_folder_icons')) {
1508: $res .= '<i class="bi bi-file-earmark-text menu-icon"></i>';
1509: }
1510: $res .= '<span class="nav-label">'.$this->trans('Compose').'</span></a></li>';
1511:
1512: if ($this->format == 'HTML5') {
1513: return $res;
1514: }
1515: $this->concat('formatted_folder_list', $res);
1516: }
1517: }
1518:
1519: /**
1520: * @subpackage
1521: */
1522: class Hm_Output_stepper_setup_server_smtp extends Hm_Output_Module {
1523: protected function output() {
1524: return '
1525: <div class="step_config-smtp_bloc mb-3" id="step_config-smtp_bloc">
1526: <label><strong>SMTP</strong></label>
1527: <div class="form-floating">
1528: <input required type="text" id="srv_setup_stepper_smtp_address" name="srv_setup_stepper_smtp_address" class="txt_fld form-control" value="" placeholder="'.$this->trans('Address').'">
1529: <label class="" for="srv_setup_stepper_smtp_address">'.$this->trans('Address').'</label>
1530: <span id="srv_setup_stepper_smtp_address-error" class="invalid-feedback"></span>
1531: </div>
1532: <div class="d-flex">
1533: <div class="flex-fill">
1534: <div class="form-floating">
1535: <input required type="number" id="srv_setup_stepper_smtp_port" name="srv_setup_stepper_smtp_port" class="txt_fld form-control" value="" placeholder="'.$this->trans('Port').'">
1536: <label class="" for="srv_setup_stepper_smtp_port">'.$this->trans('Port').'</label>
1537: <span id="srv_setup_stepper_imap_address-error" class="invalid-feedback"></span>
1538: </div>
1539: <span id="srv_setup_stepper_smtp_port-error" class="invalid-feedback"></span>
1540: </div>
1541: <div class="p-2 flex-fill">
1542: <div class="form-check">
1543: <input class="form-check-input" type="radio" id="smtp_tls" name="srv_setup_stepper_smtp_tls" value="true" checked>
1544: <label class="form-check-label" style="font-size: 12px;" for="smtp_tls">
1545: '.$this->trans('Use TLS').'
1546: </label>
1547: </div>
1548: <div class="form-check">
1549: <input class="form-check-input" type="radio" id="smtp_start_tls" name="srv_setup_stepper_smtp_tls" value="false" >
1550: <label class="form-check-label" style="font-size: 12px;" for="smtp_start_tls">
1551: '.$this->trans('STARTTLS or unencrypted').'
1552: </label>
1553: </div>
1554: </div>
1555: </div>
1556: </div>
1557: ';
1558: }
1559: }
1560:
1561: /**
1562: * Send scheduled messages
1563: * @subpackage smtp/handler
1564: */
1565: class Hm_Handler_send_scheduled_messages extends Hm_Handler_Module {
1566: /**
1567: * Send delayed messages
1568: * This should use cron
1569: */
1570: public function process() {
1571: if (!($this->module_is_supported('imap') || $this->module_is_supported('profiles'))) {
1572: return;
1573: }
1574:
1575: $servers = Hm_IMAP_List::dumpForMailbox();
1576: $scheduled_msg_count = 0;
1577:
1578: foreach ($servers as $server_id => $config) {
1579: $mailbox = new Hm_Mailbox($server_id, $this->user_config, $this->session, $config);
1580: if ($mailbox->connect()) {
1581: $folder = 'Scheduled';
1582: if (! $mailbox->folder_exists($folder)) {
1583: continue;
1584: }
1585: $ret = $mailbox->get_messages($folder, 'DATE', false, 'ALL');
1586: foreach ($ret[1] as $msg) {
1587: $msg_headers = $mailbox->get_message_headers($folder, $msg['uid']);
1588: if (! empty($msg_headers['X-Schedule'])) {
1589: $scheduled_msg_count++;
1590: } else {
1591: continue;
1592: }
1593: if (send_scheduled_message($this, $mailbox, $folder, $msg['uid'])) {
1594: $scheduled_msg_count++;
1595: }
1596: }
1597: }
1598: }
1599:
1600: $this->out('scheduled_msg_count', $scheduled_msg_count);
1601: }
1602: }
1603:
1604: /**
1605: * Changes the schedule of the message
1606: * @subpackage smtp/handler
1607: */
1608: class Hm_Handler_re_schedule_message_sending extends Hm_Handler_Module {
1609: public function process() {
1610: if (!($this->module_is_supported('imap') || $this->module_is_supported('profiles'))) {
1611: return;
1612: }
1613: list($success, $form) = $this->process_form(array('schedule_date', 'scheduled_msg_ids'));
1614: if (!$success) {
1615: return;
1616: }
1617: $scheduled_msg_count = 0;
1618: $new_schedule_date = $form['schedule_date'];
1619: if ($form['schedule_date'] != 'now') {
1620: $new_schedule_date = get_scheduled_date($form['schedule_date']);
1621: }
1622: $ids = explode(',', $form['scheduled_msg_ids']);
1623: foreach ($ids as $msg_part) {
1624: list($imap_server_id, $msg_id, $folder) = explode('_', $msg_part);
1625: $imap_server = Hm_IMAP_List::getForMailbox($imap_server_id);
1626:
1627: $mailbox = new Hm_Mailbox($imap_server_id, $this->user_config, $this->session, $imap_server);
1628: if ($mailbox->connect()) {
1629: $folder = hex2bin($folder);
1630: if (reschedule_message_sending($this, $mailbox, $msg_id, $folder, $new_schedule_date)) {
1631: $scheduled_msg_count++;
1632: }
1633: }
1634: }
1635: $this->out('scheduled_msg_count', $scheduled_msg_count);
1636: if ($scheduled_msg_count == count($ids)) {
1637: $msg = 'Operation successful';
1638: } elseif ($scheduled_msg_count > 0) {
1639: $msg = 'Some messages have been scheduled for sending';
1640: } else {
1641: $msg = 'ERRFailed to schedule sending for messages';
1642: }
1643: Hm_Msgs::add($msg);
1644: $this->save_hm_msgs();
1645: }
1646: }
1647:
1648: /**
1649: * Add scheduled send to the message list controls
1650: * @subpackage imap/output
1651: */
1652: class Hm_Output_scheduled_send_msg_control extends Hm_Output_Module {
1653: protected function output() {
1654: $parts = explode('_', $this->get('list_path'));
1655: if ($parts[0] == 'imap' && hex2bin($parts[2]) == 'Scheduled') {
1656: $res = schedule_dropdown($this, true);
1657: $this->concat('msg_controls_extra', $res);
1658: }
1659: }
1660: }
1661:
1662: /**
1663: * @subpackage smtp/functions
1664: */
1665: if (!hm_exists('smtp_server_dropdown')) {
1666: function smtp_server_dropdown($data, $output_mod, $recip, $selected_id=false) {
1667: $res = '<div class="form-floating"><select id="compose_smtp_id" name="compose_smtp_id" class="compose_server form-select" aria-label="'.$output_mod->trans('Compose SMTP ID').'">';
1668: $profiles = array();
1669: if (array_key_exists('compose_profiles', $data)) {
1670: $profiles = $data['compose_profiles'];
1671: }
1672: if (array_key_exists('smtp_servers', $data)) {
1673: $selected = false;
1674: $default = false;
1675: foreach ($data['smtp_servers'] as $id => $vals) {
1676: foreach (profiles_by_smtp_id($profiles, $vals['id']) as $index => $profile) {
1677: if ($profile['default']) {
1678: $default = $vals['id'].'.'.($index + 1);
1679: }
1680: if ((string) $selected_id === sprintf('%s.%s', $vals['id'], ($index + 1))) {
1681: $selected = $vals['id'].'.'.($index + 1);
1682: }
1683: elseif ($recip && trim($recip) == $profile['address']) {
1684: $selected = $vals['id'].'.'.($index + 1);
1685: }
1686: }
1687: if (!$selected && $selected_id !== false && $vals['id'] == $selected_id) {
1688: $selected = $vals['id'];
1689: }
1690: if (!$selected && $recip && trim($recip) == trim($vals['user'])) {
1691: $selected = $vals['id'];
1692: }
1693: }
1694: if ($selected === false && $default !== false) {
1695: $selected = $default;
1696: }
1697: foreach ($data['smtp_servers'] as $id => $vals) {
1698: $smtp_profiles = profiles_by_smtp_id($profiles, $vals['id']);
1699: if (count($smtp_profiles) > 0) {
1700: foreach ($smtp_profiles as $index => $profile) {
1701: $res .= '<option data-email="'.$profile['address'].'"';
1702: if ((string) $selected === sprintf('%s.%s', $vals['id'], ($index + 1)) || (! mb_strstr(strval($selected), '.') && strval($selected) === strval($vals['id']))) {
1703: $res .= 'selected="selected" ';
1704: }
1705: $res .= 'value="'.$output_mod->html_safe($vals['id'].'.'.($index+1)).'">';
1706: $res .= $output_mod->html_safe(sprintf('"%s" %s %s', $profile['name'], ($profile['name'] != $profile['address']) ? $profile['address']: "", ($vals['name'] != $profile['name'] && $vals['name'] != $profile['address']) ? $vals['name'] : ""));
1707: $res .= '</option>';
1708: }
1709: }
1710: else {
1711: $res .= '<option data-email="'.$vals['user'].'"';
1712: if ($selected === $id) {
1713: $res .= 'selected="selected" ';
1714: }
1715: $res .= 'value="'.$output_mod->html_safe($vals['id']).'">';
1716: $res .= $output_mod->html_safe(($vals['user'] == $vals['name']) ? $vals['user'] : sprintf("%s - %s", $vals['user'], $vals['name']));
1717: $res .= '</option>';
1718: }
1719: }
1720: }
1721: $res .= '</select><label for="compose_smtp_id">'.$output_mod->trans('Compose SMTP ID').'</label></div>';
1722: return $res;
1723: }}
1724:
1725: /**
1726: * Check for and do an Oauth2 token reset if needed
1727: * @param array $server SMTP server data
1728: * @param object $config site config object
1729: * @return mixed
1730: */
1731: if (!hm_exists('smtp_refresh_oauth2_token')) {
1732: function smtp_refresh_oauth2_token($server, $config) {
1733: if (array_key_exists('expiration', $server) && (int) $server['expiration'] <= time()) {
1734: $oauth2_data = get_oauth2_data($config);
1735: $details = array();
1736: if ($server['server'] == 'smtp.gmail.com') {
1737: $details = $oauth2_data['gmail'];
1738: }
1739: if (!empty($details)) {
1740: $oauth2 = new Hm_Oauth2($details['client_id'], $details['client_secret'], $details['client_uri']);
1741: $result = $oauth2->refresh_token($details['refresh_uri'], $server['refresh_token']);
1742: if (array_key_exists('access_token', $result)) {
1743: return array(strtotime(sprintf('+%d seconds', $result['expires_in'])), $result['access_token']);
1744: }
1745: }
1746: }
1747: return array();
1748: }}
1749:
1750: /**
1751: * @subpackage smtp/functions
1752: */
1753: if (!hm_exists('delete_uploaded_files')) {
1754: function delete_uploaded_files($session, $draft_id=false, $filename=false) {
1755: $files = $session->get('uploaded_files', array());
1756: $deleted = 0;
1757: foreach ($files as $id => $file_list) {
1758: foreach ($file_list as $file_id => $file) {
1759: if (($draft_id === false && !$filename) || $draft_id === $id || $filename === $file['basename']) {
1760: @unlink($file['filename']);
1761: $deleted++;
1762: if ($filename) {
1763: unset($files[$id][$file_id]);
1764: }
1765: }
1766: }
1767: }
1768: if ($draft_id !== false) {
1769: if (array_key_exists($draft_id, $files)) {
1770: unset($files[$draft_id]);
1771: }
1772: }
1773: elseif ($draft_id === false && !$filename) {
1774: $files = array();
1775: }
1776: $session->set('uploaded_files', $files);
1777: return $deleted;
1778: }}
1779:
1780: /**
1781: * @subpackage/functions
1782: */
1783: if (!hm_exists('get_uploaded_files')) {
1784: function get_uploaded_files($id, $session) {
1785: $files = $session->get('uploaded_files', array());
1786: if (array_key_exists($id, $files)) {
1787: return $files[$id];
1788: }
1789:
1790: return array();
1791: }}
1792:
1793: /**
1794: * @subpackage/functions
1795: */
1796: if (!hm_exists('save_uploaded_file')) {
1797: function save_uploaded_file($id, $atts, $session) {
1798: $files = $session->get('uploaded_files', array());
1799: if (array_key_exists($id, $files)) {
1800: $files[$id][] = $atts;
1801: }
1802: else {
1803: $files[$id] = array($atts);
1804: }
1805: $session->set('uploaded_files', $files);
1806: }}
1807:
1808: /**
1809: * @subpackage smtp/functions
1810: */
1811: if (!hm_exists('format_attachment_row')) {
1812: function format_attachment_row($file, $output_mod) {
1813: $unique_identifier = str_replace(' ', '_', $output_mod->html_safe($file['name']));
1814: return '<tr id="tr-'.$unique_identifier.'"><td>'.
1815: $output_mod->html_safe($file['name']).'</td><td>'.$output_mod->html_safe($file['type']).' ' .$output_mod->html_safe(round($file['size']/1024, 2)). 'KB '.
1816: '<td style="display:none"><input name="uploaded_files[]" type="text" value="'.$file['name'].'" /></td>'.
1817: '</td><td><a class="remove_attachment text-danger" id="remove-'.$unique_identifier.'" href="#">Remove</a><a style="display:none" id="pause-'.$unique_identifier.'" class="pause_upload" href="#">Pause</a><a style="display:none" id="resume-'.$unique_identifier.'" class="resume_upload" href="#">Resume</a></td></tr><tr><td colspan="2">'.
1818: '<div class="meter" style="width:100%; display: none;"><span id="progress-'.
1819: $unique_identifier.'" style="width:0%;"><span class="progress" id="progress-bar-'.
1820: $unique_identifier.'"></span></span></div></td></tr>';
1821: }}
1822:
1823: /**
1824: * @subpackage smtp/functions
1825: */
1826: if (!hm_exists('get_primary_recipient')) {
1827: function get_primary_recipient($profiles, $headers, $smtp_servers, $is_draft=False) {
1828: $addresses = array();
1829: $flds = array('to', 'delivered-to', 'x-delivered-to', 'envelope-to', 'x-original-to', 'cc', 'reply-to');
1830: if ($is_draft) {
1831: $flds = array('from', 'to', 'delivered-to', 'x-delivered-to', 'envelope-to', 'x-original-to', 'cc', 'reply-to');
1832: }
1833: $headers = lc_headers($headers);
1834: foreach ($flds as $fld) {
1835: if (array_key_exists($fld, $headers)) {
1836: $header = $headers[$fld];
1837: if (is_array($header)) {
1838: foreach ($header as $value) {
1839: foreach (process_address_fld($value) as $address) {
1840: $addresses[] = $address['email'];
1841: }
1842: }
1843: } else {
1844: foreach (process_address_fld($header) as $address) {
1845: $addresses[] = $address['email'];
1846: }
1847: }
1848: }
1849: }
1850: $addresses = array_unique($addresses);
1851: foreach ($addresses as $address) {
1852: foreach ($smtp_servers as $id => $vals) {
1853: foreach (profiles_by_smtp_id($profiles, $vals['id']) as $profile) {
1854: if ($profile['address'] == $address) {
1855: return $address;
1856: }
1857: }
1858: }
1859: }
1860: foreach ($addresses as $address) {
1861: foreach ($smtp_servers as $id => $vals) {
1862: if ($vals['user'] == $address) {
1863: return $address;
1864: }
1865: }
1866: }
1867: return false;
1868: }}
1869:
1870: /**
1871: * @subpackage/functions
1872: */
1873: if (!hm_exists('delete_draft')) {
1874: function delete_draft($id, $cache, $imap_server_id, $folder) {
1875: $mailbox = Hm_IMAP_List::get_connected_mailbox($imap_server_id);
1876: if ($mailbox && $mailbox->authed()) {
1877: if ($mailbox->message_action($folder, 'DELETE', array($id))['status']) {
1878: $mailbox->message_action($folder, 'EXPUNGE', array($id));
1879: return true;
1880: }
1881: }
1882: return false;
1883: }}
1884:
1885: /**
1886: * @subpackage smtp/functions
1887: */
1888: if (!hm_exists('find_imap_by_smtp')) {
1889: function find_imap_by_smtp($imap_profiles, $smtp_profile) {
1890: foreach ($imap_profiles as $profile) {
1891: if ($smtp_profile['user'] == $profile['user']) {
1892: return $profile;
1893: }
1894: if (explode('@', $smtp_profile['user'])[0]
1895: == explode('@', $profile['user'])[0]) {
1896: return $profile;
1897: }
1898: if ($smtp_profile['user'] == $profile['name']) {
1899: return $profile;
1900: }
1901: }
1902: }}
1903:
1904:
1905: /**
1906: * Delete a directory RECURSIVELY
1907: * @param string $dir - directory path
1908: * @link http://php.net/manual/en/function.rmdir.php
1909: */
1910: if (!hm_exists('rrmdir')) {
1911: function rrmdir($dir) {
1912: if (is_dir($dir)) {
1913: $objects = scandir($dir);
1914: foreach ($objects as $object) {
1915: if ($object != "." && $object != "..") {
1916: if (filetype($dir . "/" . $object) == "dir") {
1917: rrmdir($dir . "/" . $object);
1918: } else {
1919: unlink($dir . "/" . $object);
1920: }
1921: }
1922: }
1923: reset($objects);
1924: rmdir($dir);
1925: }
1926: }
1927: }
1928:
1929: /**
1930: *
1931: * Check if all the parts exist, and
1932: * gather all the parts of the file together
1933: * @param string $temp_dir - the temporary directory holding all the parts of the file
1934: * @param string $fileName - the original file name
1935: * @param string $chunkSize - each chunk size (in bytes)
1936: * @param string $totalSize - original file size (in bytes)
1937: * @subpackage smtp/functions
1938: */
1939: if (!hm_exists('createFileFromChunks')) {
1940: function createFileFromChunks($temp_dir, $fileName, $chunkSize, $totalSize,$total_files) {
1941: // count all the parts of this file
1942: // $fileName = Hm_Crypt::ciphertext($fileName, Hm_Request_Key::generate());
1943: $total_files_on_server_size = 0;
1944: $temp_total = 0;
1945: foreach(scandir($temp_dir) as $file) {
1946: $temp_total = $total_files_on_server_size;
1947: $tempfilesize = filesize($temp_dir.'/'.$file);
1948: $total_files_on_server_size = $temp_total + $tempfilesize;
1949: }
1950: // check that all the parts are present
1951: // If the Size of all the chunks on the server is equal to the size of the file uploaded.
1952: if ($total_files_on_server_size >= $totalSize) {
1953: // create the final destination file
1954: if (($fp = fopen($temp_dir.'/../'.$fileName, 'w')) !== false) {
1955: for ($i=1; $i<=$total_files; $i++) {
1956: fwrite($fp, file_get_contents($temp_dir.'/'.$fileName.'.part'.$i));
1957: }
1958: fclose($fp);
1959: $hashed_content = Hm_Crypt::ciphertext(file_get_contents($temp_dir.'/../'.$fileName), Hm_Request_Key::generate());
1960: file_put_contents($temp_dir.'/../'.$fileName, $hashed_content);
1961: } else {
1962: return false;
1963: }
1964:
1965: // rename the temporary directory (to avoid access from other
1966: // concurrent chunks uploads) and than delete it
1967: if (rename($temp_dir, $temp_dir.'_UNUSED')) {
1968: rrmdir($temp_dir.'_UNUSED');
1969: } else {
1970: rrmdir($temp_dir);
1971: }
1972: }
1973: return true;
1974: }
1975: }
1976:
1977: /**
1978: * @subpackage smtp/functions
1979: */
1980: if (!hm_exists('get_uploaded_files_from_array')) {
1981: function get_uploaded_files_from_array($uploaded_files) {
1982: $parsed_files = [];
1983: foreach($uploaded_files as $file) {
1984: if (is_array($file)) {
1985: $parsed_files[] = $file;
1986: } else {
1987: $parsed_path = explode('/', $file);
1988: $parsed_files[] = [
1989: 'filename' => $file,
1990: 'type' => get_mime_type($file),
1991: 'name' => end($parsed_path)
1992: ];
1993: }
1994: }
1995: return $parsed_files;
1996: }
1997: }
1998:
1999: function prepare_draft_mime($atts, $uploaded_files, $from = false, $name = '', $profile_id = null) {
2000: $uploaded_files = get_uploaded_files_from_array($uploaded_files);
2001: $mime = new Hm_MIME_Msg(
2002: $atts['draft_to'],
2003: $atts['draft_subject'],
2004: $atts['draft_body'],
2005: $from,
2006: false,
2007: $atts['draft_cc'],
2008: $atts['draft_bcc'],
2009: '',
2010: $name,
2011: $atts['draft_in_reply_to'],
2012: $atts['delivery_receipt'],
2013: $atts['schedule'],
2014: $profile_id
2015: );
2016:
2017: $mime->add_attachments($uploaded_files);
2018:
2019: return $mime;
2020: }
2021:
2022: /**
2023: * @subpackage smtp/functions
2024: */
2025: if (!hm_exists('save_imap_draft')) {
2026: function save_imap_draft($atts, $id, $session, $mod, $mod_cache, $uploaded_files, $profile) {
2027: $imap_profile = false;
2028: $from = false;
2029: $name = '';
2030: $uploaded_files = get_uploaded_files_from_array($uploaded_files);
2031:
2032: if ($profile && $profile['type'] == 'imap' && $mod->module_is_supported('imap')) {
2033: $from = $profile['replyto'];
2034: $name = $profile['name'];
2035: $imap_profile = Hm_IMAP_List::fetch($profile['user'], $profile['server']);
2036: }
2037: if (!$imap_profile || empty($imap_profile)) {
2038: $imap_profile = find_imap_by_smtp(
2039: $mod->user_config->get('imap_servers'),
2040: $mod->user_config->get('smtp_servers')[$atts['draft_smtp']]
2041: );
2042: if ($imap_profile) {
2043: $from = $mod->user_config->get('smtp_servers')[$atts['draft_smtp']]['user'];
2044: }
2045: }
2046: if (empty($imap_profile)) {
2047: return -1;
2048: }
2049:
2050: $imap_profile = Hm_IMAP_List::getForMailbox($imap_profile['id']);
2051: $specials = get_special_folders($mod, $imap_profile['id']);
2052:
2053: if ((!array_key_exists('draft', $specials) || !$specials['draft']) && !array_key_exists('schedule', $atts)) {
2054: Hm_Msgs::add('There is no draft directory configured for this account.', 'warning');
2055: return -1;
2056: }
2057: $mailbox = new Hm_Mailbox($imap_profile['id'], $mod->user_config, $session, $imap_profile);
2058:
2059: if (! $mailbox->connect()) {
2060: return -1;
2061: }
2062:
2063: if (!empty($atts['schedule'])) {
2064: $folder ='Scheduled';
2065: if (!$mailbox->folder_exists($folder)) {
2066: $mailbox->create_folder($folder);
2067: }
2068: $atts['schedule'] = get_scheduled_date($atts['schedule']);
2069: } else {
2070: $folder = $specials['draft'];
2071: }
2072:
2073: $mime = prepare_draft_mime($atts, $uploaded_files, $from, $name, $profile['id']);
2074: $res = $mime->process_attachments();
2075:
2076: if (! empty($atts['schedule']) && empty($mime->get_recipient_addresses())) {
2077: Hm_Msgs::add("ERRNo valid recipients found");
2078: return -1;
2079: }
2080:
2081: $msg = str_replace("\r\n", "\n", $mime->get_mime_msg());
2082: $msg = str_replace("\n", "\r\n", $msg);
2083: $msg = rtrim($msg)."\r\n";
2084:
2085: if (! $mailbox->store_message($folder, $msg, false, true)) {
2086: Hm_Msgs::add('An error occurred saving the draft message', 'danger');
2087: return -1;
2088: }
2089:
2090: $messages = $mailbox->get_messages($folder, 'ARRIVAL', true, 'DRAFT', 0, 10);
2091:
2092: // Remove old version from the mailbox
2093: if ($id) {
2094: $mailbox->message_action($folder, 'DELETE', array($id));
2095: $mailbox->message_action($folder, 'EXPUNGE', array($id));
2096: }
2097: foreach ($messages[1] as $mail) {
2098: $msg_header = $mailbox->get_message_headers($folder, $mail['uid']);
2099: // Convert all header keys to lowercase
2100: $msg_header_lower = array_change_key_case($msg_header, CASE_LOWER);
2101: $mime_headers_lower = array_change_key_case($mime->get_headers(), CASE_LOWER);
2102: if (!empty($msg_header_lower['message_id']) && !empty($mime_headers_lower['message_id'])) {
2103: if (trim($msg_header_lower['message_id']) === trim($mime_headers_lower['message_id'])) {
2104: return $mail['uid'];
2105: }
2106: }
2107: if (!empty($msg_header_lower['message-id']) && !empty($mime_headers_lower['message-id'])) {
2108: $msg_message_id = trim(str_replace(array('<', '>'), '', trim($msg_header_lower['message-id'])));
2109: $msg_mime_id = trim(str_replace(array('<', '>'), '', trim($mime_headers_lower['message-id'])));
2110: if (trim($msg_message_id) === trim($msg_mime_id)) {
2111: return $mail['uid'];
2112: }
2113: }
2114: }
2115: return -1;
2116: }}
2117:
2118: /**
2119: * @subpackage smtp/functions
2120: */
2121: if (!hm_exists('get_draft')) {
2122: function get_draft($id, $session) {
2123: $drafts = $session->get('compose_drafts', array());
2124: if (array_key_exists($id, $drafts)) {
2125: return $drafts[$id];
2126: }
2127: return false;
2128: }}
2129:
2130: /**
2131: * @subpackage smtp/functions
2132: */
2133: if (!hm_exists('next_draft_key')) {
2134: function next_draft_key($session) {
2135: $drafts = $session->get('compose_drafts', array());
2136: if (count($drafts)) {
2137: return max(array_keys($drafts))+1;
2138: } else {
2139: return 0;
2140: }
2141: }}
2142:
2143: /**
2144: * @subpackage smtp/functions
2145: */
2146: if (!hm_exists('get_outbound_msg_detail')) {
2147: function get_outbound_msg_detail($post, $draft, $body_type) {
2148: $body = '';
2149: $cc = '';
2150: $bcc = '';
2151: $in_reply_to = '';
2152:
2153: if (array_key_exists('compose_body', $post)) {
2154: $body = $post['compose_body'];
2155: $draft['draft_body'] = $post['compose_body'];
2156: }
2157: if (array_key_exists('compose_cc', $post)) {
2158: $cc = $post['compose_cc'];
2159: $draft['draft_cc'] = $post['compose_cc'];
2160: }
2161: if (array_key_exists('compose_bcc', $post)) {
2162: $bcc = $post['compose_bcc'];
2163: $draft['draft_bcc'] = $post['compose_bcc'];
2164: }
2165: if (array_key_exists('compose_in_reply_to', $post)) {
2166: $in_reply_to = $post['compose_in_reply_to'];
2167: $draft['draft_in_reply_to'] = $post['compose_in_reply_to'];
2168: }
2169: if ($body_type == 2) {
2170: $converter = new GithubFlavoredMarkdownConverter([
2171: 'html_input' => 'strip',
2172: 'allow_unsafe_links' => false,
2173: ]);
2174: $body = $converter->convert($body);
2175: }
2176: return array($body, $cc, $bcc, $in_reply_to, $draft);
2177: }}
2178:
2179: /**
2180: * @subpackage smtp/functions
2181: */
2182: if (!hm_exists('get_outbound_msg_profile_detail')) {
2183: function get_outbound_msg_profile_detail($form, $profiles, $smtp_details, $hmod) {
2184: $imap_server = false;
2185: $from_name = '';
2186: $reply_to = '';
2187: $from = $smtp_details['user'];
2188: $profile = profile_from_compose_smtp_id($profiles, $form['compose_smtp_id']);
2189: if ($profile) {
2190: if ($profile['type'] == 'imap' && $hmod->module_is_supported('imap')) {
2191: $imap = Hm_IMAP_List::fetch($profile['user'], $profile['server']);
2192: if ($imap) {
2193: $imap_server = $imap['id'];
2194: }
2195: }
2196: $from_name = $profile['name'];
2197: $reply_to = $profile['replyto'];
2198: if ($profile['address']) {
2199: $from = $profile['address'];
2200: }
2201: }
2202: if ($from == $smtp_details['user'] && mb_strpos($from, '@') === false) {
2203: if (array_key_exists('HTTP_HOST', $hmod->request->server)) {
2204: $from .= sprintf('@%s', $hmod->request->server['HTTP_HOST']);
2205: }
2206: }
2207: return array($imap_server, $from_name, $reply_to, $from);
2208: }}
2209:
2210: /**
2211: * @subpackage smtp/functions
2212: */
2213: if (!hm_exists('smtp_refresh_oauth2_token_on_send')) {
2214: function smtp_refresh_oauth2_token_on_send($smtp_details, $mod, $smtp_id) {
2215: if (array_key_exists('auth', $smtp_details) && $smtp_details['auth'] == 'xoauth2') {
2216: $results = smtp_refresh_oauth2_token($smtp_details, $mod->config);
2217: if (!empty($results)) {
2218: if (Hm_SMTP_List::update_oauth2_token($smtp_id, $results[1], $results[0])) {
2219: Hm_Debug::add(sprintf('Oauth2 token refreshed for SMTP server id %s', $smtp_id), 'info');
2220: Hm_SMTP_List::save();
2221: }
2222: }
2223: }
2224: }}
2225:
2226: /*
2227: * @subpackage smtp/functions
2228: */
2229: if (!hm_exists('outbound_address_check')) {
2230: function outbound_address_check($mod, $from, $reply_to) {
2231: $domain = $mod->config->get('default_email_domain');
2232: if (!$domain) {
2233: if (array_key_exists('HTTP_HOST', $mod->request->server)) {
2234: $domain = $mod->request->server['HTTP_HOST'];
2235: }
2236: }
2237: if ($domain) {
2238: if (mb_strpos($from, '@') === false) {
2239: $from = $from.'@'.$domain;
2240: }
2241: if (!trim($reply_to)) {
2242: $reply_to = $from;
2243: }
2244: elseif (mb_strpos($reply_to, '@') === false) {
2245: $reply_to = $reply_to.'@'.$domain;
2246: }
2247: }
2248: return array($from, $reply_to);
2249: }}
2250:
2251: /**
2252: * @subpackage smtp/functions
2253: */
2254: if (!hm_exists('repopulate_compose_form')) {
2255: function repopulate_compose_form($draft, $handler_mod) {
2256: $handler_mod->out('no_redirect', true);
2257: $handler_mod->out('compose_draft', $draft);
2258: if (array_key_exists('compose_msg_path', $handler_mod->request->post)
2259: && $handler_mod->request->post['compose_msg_path']) {
2260: $handler_mod->out('compose_msg_path', $handler_mod->request->post['compose_msg_path']);
2261: }
2262: if (array_key_exists('compose_msg_uid', $handler_mod->request->post)
2263: && $handler_mod->request->post['compose_msg_uid']) {
2264: $handler_mod->out('compose_msg_uid', $handler_mod->request->post['compose_msg_uid']);
2265: }
2266: }}
2267:
2268: /**
2269: * @subpackage smtp/functions
2270: */
2271: if (!hm_exists('server_from_compose_smtp_id')) {
2272: function server_from_compose_smtp_id($id) {
2273: $pos = mb_strpos($id, '.');
2274: if ($pos === false) {
2275: return $id;
2276: }
2277: return mb_substr($id, 0, $pos);
2278: }}
2279:
2280: /**
2281: * @subpackage smtp/functions
2282: */
2283: if (!hm_exists('profile_from_compose_smtp_id')) {
2284: function profile_from_compose_smtp_id($profiles, $id) {
2285: if (mb_strpos($id, '.') === false) {
2286: return false;
2287: }
2288: $smtp_id = server_from_compose_smtp_id($id);
2289: $profiles = profiles_by_smtp_id($profiles, $smtp_id);
2290: foreach ($profiles as $index => $profile) {
2291: if ((string) $id === sprintf('%s.%s', $smtp_id, ($index+1))) {
2292: return $profile;
2293: }
2294: }
2295: return false;
2296: }}
2297:
2298: /**
2299: * @subpackage smtp/functions
2300: */
2301: if (!hm_exists('parse_mailto')) {
2302: function parse_mailto($str) {
2303: $res = array(
2304: 'draft_to' => '',
2305: 'draft_cc' => '',
2306: 'draft_bcc' => '',
2307: 'draft_subject' => '',
2308: 'draft_body' => ''
2309: );
2310: $mailto = parse_url(urldecode($str));
2311: if (!is_array($mailto) || !array_key_exists('path', $mailto) || !$mailto['path']) {
2312: return $res;
2313: }
2314: $res['draft_to'] = $mailto['path'];
2315: if (!array_key_exists('query', $mailto) || !$mailto['query']) {
2316: return $res;
2317: }
2318: parse_str($mailto['query'], $args);
2319: foreach ($args as $name => $val) {
2320: $res['draft_'.$name] = $val;
2321: }
2322: return $res;
2323: }}
2324:
2325: /**
2326: * @subpackage smtp/functions
2327: */
2328: if (!hm_exists('default_smtp_server')) {
2329: function default_smtp_server($user_config, $session, $request, $config, $user, $pass) {
2330: $smtp_server = $config->get('default_smtp_server', false);
2331: if (!$smtp_server) {
2332: return;
2333: }
2334: $smtp_port = $config->get('default_smtp_port', 465);
2335: $smtp_tls = $config->get('default_smtp_tls', true);
2336: Hm_SMTP_List::init($user_config, $session);
2337: $attributes = array(
2338: 'name' => $config->get('default_smtp_name', 'Default'),
2339: 'default' => true,
2340: 'type' => 'smtp',
2341: 'server' => $smtp_server,
2342: 'port' => $smtp_port,
2343: 'tls' => $smtp_tls,
2344: 'user' => $user,
2345: 'pass' => $pass
2346: );
2347: if ($config->get('default_smtp_no_auth', false)) {
2348: $attributes['no_auth'] = true;
2349: }
2350: Hm_SMTP_List::add($attributes);
2351: Hm_Debug::add('Default SMTP server added', 'info');
2352: }}
2353:
2354: /**
2355: * @subpackage smtp/functions
2356: */
2357: if (!hm_exists('recip_count_check')) {
2358: function recip_count_check($headers, $omod) {
2359: $headers = lc_headers($headers);
2360: $recip_count = 0;
2361:
2362: if (array_key_exists('to', $headers) && $headers['to']) {
2363: $recip_count += count(process_address_fld($headers['to']));
2364: }
2365:
2366: if (array_key_exists('cc', $headers) && $headers['cc']) {
2367: $recip_count += count(process_address_fld($headers['cc']));
2368: }
2369: if ($recip_count > MAX_RECIPIENT_WARNING) {
2370: Hm_Msgs::add('Message contains more than the maximum number of recipients, proceed with caution', 'warning');
2371: }
2372: }}
2373: