source: subversion/branches/devel-vnext/program/steps/mail/sendmail.inc @ 626

Last change on this file since 626 was 626, checked in by till, 6 years ago

+ split rcube_contatcs.inc into another file rcube/result_set. (one class per file)
+ fixed cs on rcube_contacts and result_set
+ fixed cs and references in addcontact

  • removed some debug code from the app

# fixed encoding issue with special characters on reply/forward/compose
# fixed some issues with orphaned class/function references and use of registry
# lists in mailboxlist where nested which lead to css/js issues - removed that

  • todo: found an issue where a socket timeout appears in lib/Net/Socket - need to watch that
  • hope i didn't forget anything ;)
  • Property svn:executable set to *
File size: 17.7 KB
Line 
1<?php
2
3/*
4 +-----------------------------------------------------------------------+
5 | program/steps/mail/sendmail.inc                                       |
6 |                                                                       |
7 | This file is part of the RoundCube Webmail client                     |
8 | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
9 | Licensed under the GNU GPL                                            |
10 |                                                                       |
11 | PURPOSE:                                                              |
12 |   Compose a new mail message with all headers and attachments         |
13 |   and send it using IlohaMail's SMTP methods or with PHP mail()       |
14 |                                                                       |
15 +-----------------------------------------------------------------------+
16 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
17 +-----------------------------------------------------------------------+
18
19 $Id: sendmail.inc 556 2007-05-13 18:25:52Z thomasb $
20
21*/
22
23rc_main::tfk_debug('Yay, sendmail.inc reached!');
24
25
26$registry = rc_registry::getInstance();
27$OUTPUT   = $registry->get('OUTPUT', 'core');
28$MBSTRING = $registry->get('MBSTRING', 'core');
29$CONFIG   = $registry->get('CONFIG', 'core');
30$IMAP     = $registry->get('IMAP', 'core');
31
32//require_once('lib/smtp.inc');
33require_once 'include/rcube_smtp.inc';
34require_once 'lib/html2text.inc';
35require_once 'lib/rc_mail_mime.inc';
36
37
38if (!isset($_SESSION['compose']['id'])) {
39    rc_main::rcmail_overwrite_action('list');
40    return;
41}
42
43//rc_main::tfk_debug('Still here!');
44
45/****** message sending functions ********/
46require_once 'include/rcube/rcmail_send.php';
47
48//rc_main::tfk_debug('Passed require of class rc_mail_send.');
49
50if (strlen($_POST['_draft_saveid']) > 3) {
51    $olddraftmessageid = rc_main::get_input_value('_draft_saveid', RCUBE_INPUT_POST);
52}
53$message_id = sprintf(
54                '<%s@%s>',
55                md5(uniqid('rcmail' . rand(),true)),
56                rc_main::rcmail_mail_domain($_SESSION['imap_host'])
57);
58$savedraft = ((empty($_POST['_draft']) === false) ? TRUE : FALSE);
59
60//rc_main::tfk_debug('Draft?: ' . var_export($savedraft, true));
61
62// remove all scripts and act as called in frame
63$OUTPUT->reset();
64$OUTPUT->framed = TRUE;
65
66
67/****** check submission and compose message ********/
68
69
70if (!$savedraft && empty($_POST['_to']) && empty($_POST['_subject']) && $_POST['_message']) {
71    $OUTPUT->show_message("sendingfailed", 'error');
72    $OUTPUT->send('iframe');
73    return;
74}
75
76//rc_main::tfk_debug('Passed some checks! Right before charset!');
77
78// set default charset
79$input_charset = $OUTPUT->get_charset();
80$message_charset = isset($_POST['_charset']) ? $_POST['_charset'] : $input_charset;
81
82$mailto_regexp = array('/[,;]\s*[\r\n]+/', '/[\r\n]+/', '/[,;]\s*$/m', '/;/');
83$mailto_replace = array(', ', ', ', '', ',');
84
85// replace new lines and strip ending ', '
86$mailto = preg_replace(
87            $mailto_regexp,
88            $mailto_replace,
89            rc_main::get_input_value('_to', RCUBE_INPUT_POST, TRUE, $message_charset)
90);
91
92//rc_main::tfk_debug('We just replaced line endings.');
93
94// decode address strings
95$to_address_arr = $IMAP->decode_address_list($mailto);
96//rc_main::tfk_debug('To: ' . var_export($to_address_arr, true));
97
98$identity_arr = rcmail_send::get_identity(rc_main::get_input_value('_from', RCUBE_INPUT_POST));
99if ($identity_arr === false) {
100    $OUTPUT->show_message("sendingfailed", 'error');
101    $OUTPUT->send('iframe');
102    return;
103}
104
105//rc_main::tfk_debug('We got identity.');
106
107$from = $identity_arr['mailto'];
108$first_to = is_array($to_address_arr[0]) ? $to_address_arr[0]['mailto'] : $mailto;
109
110if (empty($identity_arr['string'])) {
111    $identity_arr['string'] = $from;
112}
113// compose headers array
114$headers = array(
115            'Date' => date('D, j M Y H:i:s O'),
116            'From' => rc_main::rcube_charset_convert($identity_arr['string'], RCMAIL_CHARSET, $message_charset),
117            'To'   => $mailto
118);
119
120// additional recipients
121if (!empty($_POST['_cc'])) {
122    $headers['Cc'] = preg_replace(
123                        $mailto_regexp,
124                        $mailto_replace,
125                        rc_main::get_input_value(
126                            '_cc',
127                            RCUBE_INPUT_POST,
128                            TRUE, $message_charset
129                        )
130    );
131}
132if (!empty($_POST['_bcc'])) {
133    $headers['Bcc'] = preg_replace(
134                        $mailto_regexp, $mailto_replace,
135                        rc_main::get_input_value('_bcc', RCUBE_INPUT_POST, TRUE, $message_charset)
136    );
137}
138if (empty($identity_arr['bcc']) === false) {
139     $headers['Bcc'] = ($headers['Bcc'] ? $headers['Bcc'].', ' : '') . $identity_arr['bcc'];
140}
141// add subject
142$headers['Subject'] = trim(
143                        rc_main::get_input_value(
144                            '_subject',
145                            RCUBE_INPUT_POST,
146                            FALSE,
147                            $message_charset
148                        )
149);
150
151if (empty($identity_arr['organization']) === false) {
152    $headers['Organization'] = $identity_arr['organization'];
153}
154if (empty($identity_arr['reply-to']) === false) {
155    $headers['Reply-To'] = $identity_arr['reply-to'];
156}
157if (empty($_SESSION['compose']['reply_msgid']) === false) {
158    $headers['In-Reply-To'] = $_SESSION['compose']['reply_msgid'];
159}
160if (empty($_SESSION['compose']['references']) === false) {
161    $headers['References'] = $_SESSION['compose']['references'];
162}
163if (empty($_POST['_priority']) === false) {
164    $priority = (int)$_POST['_priority'];
165    $a_priorities = array(1=>'highest', 2=>'high', 4=>'low', 5=>'lowest');
166    if ($str_priority = $a_priorities[$priority]) {
167        $headers['X-Priority'] = sprintf(
168                                    "%d (%s)",
169                                    $priority,
170                                    ucfirst($str_priority)
171        );
172    }
173}
174
175if (!empty($_POST['_receipt'])) {
176    $headers['Return-Receipt-To']           = $identity_arr['string'];
177    $headers['Disposition-Notification-To'] = $identity_arr['string'];
178}
179
180// additional headers
181$headers['Message-ID'] = $message_id;
182$headers['X-Sender']   = $from;
183
184if (!empty($CONFIG['useragent'])) {
185    $headers['User-Agent'] = $CONFIG['useragent'];
186}
187// fetch message body
188$message_body = rc_main::get_input_value(
189                    '_message',
190                    RCUBE_INPUT_POST,
191                    TRUE,
192                    $message_charset
193);
194
195// append generic footer to all messages
196if (!empty($CONFIG['generic_message_footer'])) {
197    $file = realpath($CONFIG['generic_message_footer']);
198    if(($fp = @fopen($file, 'r')) !== false) {
199        $content = fread($fp, filesize($file));
200        fclose($fp);
201        $message_body .= "\r\n";
202        $message_body .= rc_main::rcube_charset_convert(
203                            $content,
204                            'UTF-8',
205                            $message_charset
206        );
207    }
208}
209
210// try to autodetect operating system and use the correct line endings
211// use the configured delimiter for headers
212if (!empty($CONFIG['mail_header_delimiter'])) {
213    $header_delm = $CONFIG['mail_header_delimiter'];
214}
215elseif (strtolower(substr(PHP_OS, 0, 3)=='win')) {
216    $header_delm = "\r\n";
217}
218elseif (strtolower(substr(PHP_OS, 0, 3) == 'mac')) {
219    $header_delm = "\r\n";
220}
221else {
222    $header_delm = "\n";
223}
224
225$isHtmlVal = strtolower(rc_main::get_input_value('_is_html', RCUBE_INPUT_POST));
226$isHtml    = ($isHtmlVal == "1");
227
228// create extended PEAR::Mail_mime instance
229$MAIL_MIME = new rc_mail_mime($header_delm);
230
231// For HTML-formatted messages, construct the MIME message with both
232// the HTML part and the plain-text part
233
234$error_msg = array();
235
236if ($isHtml) {
237    $status = $MAIL_MIME->setHTMLBody($message_body);
238    if ($status !== true) {
239        array_push($error_msg, 'Unable to set HTML body.');
240    }
241
242    // add a plain text version of the e-mail as an alternative part.
243    $h2t           = new html2text($message_body);
244    $plainTextPart = wordwrap($h2t->get_text(), 998, "\r\n", true);
245    $status        = $MAIL_MIME->setTXTBody($plainTextPart);
246
247    // look for "emoticon" images from TinyMCE and copy into message as attachments
248    $status = rc_mail::attach_emoticons($MAIL_MIME);
249    if ($status === false) {
250        $OUTPUT->show_message("emoticonerror", 'error');
251        $OUTPUT->send('iframe');
252        return;
253    }
254}
255else {
256    $message_body = wordwrap($message_body, 75, "\r\n");
257    $message_body = wordwrap($message_body, 998, "\r\n", true);
258    $status = $MAIL_MIME->setTXTBody($message_body, FALSE, TRUE);
259    if ($status !== true) {
260        array_push($error_msg, 'Unable to set TXT body.');
261    }
262}
263
264
265// add stored attachments, if any
266if (is_array($_SESSION['compose']['attachments'])) {
267    foreach ($_SESSION['compose']['attachments'] as $attachment) {
268        if (empty($attachment['path'])) {
269            continue;
270        }
271        $status = $MAIL_MIME->addAttachment(
272                        $attachment['path'],
273                        $attachment['mimetype'],
274                        $attachment['name'],
275                        true,
276                        'base64',
277                        'attachment',
278                        $message_charset
279        );
280        if (PEAR::isError($status)) {
281            array_push(
282                $error_msg,
283                $status->getMessage() . "\n" . var_export($attachment, true)
284            );
285        }
286    }
287}
288// add submitted attachments
289if (is_array($_FILES['_attachments']['tmp_name'])) {
290    foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) {
291        $status = $MAIL_MIME->addAttachment(
292                        $filepath,
293                        $files['type'][$i],
294                        $files['name'][$i],
295                        true,
296                        'base64',
297                        'attachment',
298                        $message_charset
299        );
300        if (PEAR::isError($status)) {
301            array_push(
302                $error_msg,
303                $status->getMessage() . "\n" . var_export($files, true)
304            );
305        }
306    }
307}
308
309//rc_main::tfk_debug('Errors anyone?: ' . var_export($error_msg, true));
310
311if (count($error_msg) > 0) {
312    raise_error(
313        array(
314            'code' => 800,
315            'type' => 'smtp',
316            'line' => __LINE__,
317            'file' => __FILE__,
318            'message' => "MAIL error: " . implode("\n", $error_msg)
319        ),
320        TRUE,
321        FALSE
322    );
323    $OUTPUT->show_message(implode("\n", $error_msg), 'error');
324    $OUTPUT->send('iframe');
325    return;
326}
327
328
329// chose transfer encoding
330$charset_7bit = array('ASCII', 'ISO-2022-JP', 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-15');
331$transfer_encoding = in_array(strtoupper($message_charset), $charset_7bit) ? '7bit' : '8bit';
332
333// encoding settings for mail composing
334$message_param = array(
335    'text_encoding' => $transfer_encoding,
336    'html_encoding' => 'quoted-printable',
337    'head_encoding' => 'quoted-printable',
338    'head_charset'  => $message_charset,
339    'html_charset'  => $message_charset,
340    'text_charset'  => $message_charset,
341);
342
343// compose message body and get headers
344$msg_body = $MAIL_MIME->get($message_param);
345// unset to save memory.
346unset($MAIL_MIME->_parts);
347
348// encoding subject header with mb_encode provides better results with asian characters
349if ($MBSTRING && function_exists("mb_encode_mimeheader")) {
350    mb_internal_encoding($message_charset);
351    $mb_subject = mb_encode_mimeheader($headers['Subject'], $message_charset, 'Q');
352    mb_internal_encoding(RCMAIL_CHARSET);
353}
354
355rc_main::tfk_debug('Right before sending/draft if!');
356
357// Begin SMTP Delivery Block
358if ($savedraft === false) {
359
360    //rc_main::tfk_debug('Not a draft. We try to send mail.');
361
362    // send thru SMTP server using custom SMTP library
363    if ($_SESSION['smtp_server'] != 'phpMail') {
364
365        //rc_main::tfk_debug('Because we can: SMTP.');
366
367        // generate list of recipients
368        $a_recipients = array($mailto);
369
370        if (strlen($headers['Cc'])) {
371            $a_recipients[] = $headers['Cc'];
372        }
373        if (strlen($headers['Bcc'])) {
374            $a_recipients[] = $headers['Bcc'];
375        }
376        // clean Bcc from header for recipients
377        $send_headers = $headers;
378        unset($send_headers['Bcc']);
379
380        if (!empty($mb_subject)) {
381            $send_headers['Subject'] = $mb_subject;
382        }
383        // send message
384        $smtp_response = array();
385        $sent = smtp_mail(
386                    $from,
387                    $a_recipients,
388                    $MAIL_MIME->txtHeaders($send_headers),
389                    $msg_body,
390                    $smtp_response
391        );
392        //rc_main::tfk_debug(var_export($smtp_response, true));
393        // log error
394        if (!$sent) {
395            raise_error(
396                array(
397                    'code' => 800,
398                    'type' => 'smtp',
399                    'line' => __LINE__,
400                    'file' => __FILE__,
401                    'message' => "SMTP error: ".join("\n", $smtp_response)
402                ),
403                TRUE,
404                FALSE
405            );
406        }
407    }
408    else { // send mail using PHP's mail() function
409
410        //rc_main::tfk_debug('We try to send using mail().');
411
412        // unset some headers because they will be added by the mail() function
413        $headers_enc = $MAIL_MIME->headers($headers);
414        $headers_php = $MAIL_MIME->_headers;
415        unset($headers_php['To'], $headers_php['Subject']);
416
417        if (!empty($mb_subject)) {
418            $headers_enc['Subject'] = $mb_subject;
419        }
420        // reset stored headers and overwrite
421        $MAIL_MIME->_headers = array();
422        $header_str = $MAIL_MIME->txtHeaders($headers_php);
423
424        if (ini_get('safe_mode')) {
425            $sent = mail(
426                        $headers_enc['To'],
427                        $headers_enc['Subject'],
428                        $msg_body,
429                        $header_str
430            );
431        }
432        else {
433            $sent = mail(
434                        $headers_enc['To'],
435                        $headers_enc['Subject'],
436                        $msg_body,
437                        $header_str,
438                        "-f$from"
439            );
440        }
441        // return to compose page if sending failed
442        if ($sent === false) {
443            //rc_main::tfk_debug('mail(): failed');
444            $OUTPUT->show_message("sendingfailed", 'error');
445            $OUTPUT->send('iframe');
446            return;
447        }
448    } // End of SMTP Delivery Block
449    // set repliead flag
450    if ($_SESSION['compose']['reply_uid']) {
451        $IMAP->set_flag($_SESSION['compose']['reply_uid'], 'ANSWERED');
452    }
453}
454// Determine which folder to save message
455if ($savedraft) {
456    $store_target = 'drafts_mbox';
457}
458else {
459  $store_target = 'sent_mbox';
460}
461
462if ($CONFIG[$store_target]) {
463    // create string of complete message headers
464    $header_str = $MAIL_MIME->txtHeaders($headers);
465
466    // check if mailbox exists
467    if (!in_array_nocase($CONFIG[$store_target], $IMAP->list_mailboxes())) {
468        $store_folder = $IMAP->create_mailbox($CONFIG[$store_target], TRUE);
469    }
470    else {
471        $store_folder = TRUE;
472    }
473
474    // add headers to message body
475    $msg_body = $header_str."\r\n".$msg_body;
476
477    // append message to sent box
478    if ($store_folder) {
479        $saved = $IMAP->save_message($CONFIG[$store_target], $msg_body);
480    }
481    // raise error if saving failed
482    if (!$saved) {
483        raise_error(
484            array(
485                'code' => 800,
486                'type' => 'imap',
487                'file' => __FILE__,
488                'message' => "Could not save message in $CONFIG[$store_target]"
489            ),
490            TRUE,
491            FALSE
492        );
493        $OUTPUT->show_message('errorsaving', 'error');
494        $OUTPUT->send('iframe');
495    }
496
497    if ($olddraftmessageid) {
498        // delete previous saved draft
499        $a_deleteid = $IMAP->search(
500                            $CONFIG['drafts_mbox'],
501                            'HEADER Message-ID',
502                            $olddraftmessageid
503        );
504        $deleted = $IMAP->delete_message(
505                            $IMAP->get_uid($a_deleteid[0],$CONFIG['drafts_mbox']),
506                            $CONFIG['drafts_mbox']
507        );
508        // raise error if deletion of old draft failed
509        if (!$deleted) {
510            raise_error(
511                    array(
512                        'code' => 800,
513                        'type' => 'imap',
514                        'file' => __FILE__,
515                        'message' => "Could not delete message from ".$CONFIG['drafts_mbox']
516                    ),
517                    TRUE,
518                    FALSE
519            );
520        }
521    }
522}
523
524if ($savedraft) {
525    // display success
526    $OUTPUT->show_message('messagesaved', 'confirmation');
527
528    // update "_draft_saveid" and the "cmp_hash" to prevent "Unsaved changes" warning
529    $OUTPUT->command('set_draft_id', str_replace(array('<','>'), "", $message_id));
530    $OUTPUT->command('compose_field_hash', true);
531
532    // start the auto-save timer again
533    $OUTPUT->command('auto_save_start');
534
535    $OUTPUT->send('iframe');
536}
537else {
538    if ($CONFIG['smtp_log'] === true) {
539        $log_entry = sprintf(
540                        "[%s] User: %d on %s; Message for %s; %s\n",
541                        date("d-M-Y H:i:s O", mktime()),
542                        $_SESSION['user_id'],
543                        $_SERVER['REMOTE_ADDR'],
544                        $mailto,
545                        !empty($smtp_response) ? join('; ', $smtp_response) : ''
546        );
547
548        if ($fp = @fopen($CONFIG['log_dir'].'/sendmail', 'a')) {
549            fwrite($fp, $log_entry);
550            fclose($fp);
551        }
552    }
553    rcmail_compose_cleanup();
554    $OUTPUT->command('sent_successfully', rcube_label('messagesent'));
555    $OUTPUT->send('iframe');
556}
557?>
Note: See TracBrowser for help on using the repository browser.