diff -Naur roundcubemail-0.1/program/include/rcube_imap.inc roundcubemail-0.1.attach/program/include/rcube_imap.inc --- roundcubemail-0.1/program/include/rcube_imap.inc 2008-02-12 07:06:26.000000000 -0700 +++ roundcubemail-0.1.attach/program/include/rcube_imap.inc 2008-03-07 13:47:56.000000000 -0700 @@ -1254,6 +1254,58 @@ /** + * Read message body of a specific message from the server and write + * to the specified file pointer + * + * @param file Open file pointer + * @param int Message UID + * @param string Part number + * @param object rcube_message_part Part object created by get_structure() + * @return bool True on success, False on failure + */ + function &write_message_part_to_fp($fp, $uid, $part=1, $o_part=NULL) + { + if (!($msg_id = $this->_uid2id($uid))) + return FALSE; + + // get part encoding if not provided + if (!is_object($o_part)) + { + $structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); + $structure = iml_GetRawStructureArray($structure_str); + $part_type = iml_GetPartTypeCode($structure, $part); + $o_part = new rcube_message_part; + $o_part->ctype_primary = $part_type==0 ? 'text' : ($part_type==2 ? 'message' : 'other'); + $o_part->encoding = strtolower(iml_GetPartEncodingString($structure, $part)); + $o_part->charset = iml_GetPartCharset($structure, $part); + } + + if ( $o_part->encoding == 'base64' ) + return iil_C_WriteBase64BodyToFP($this->conn, $this->mailbox, $msg_id, $part, $fp); + + $body = iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, 1); + + // decode part body + if ($o_part->encoding) + $body = $this->mime_decode($body, $o_part->encoding); + + // convert charset (if text or message part) + if ($o_part->ctype_primary=='text' || $o_part->ctype_primary=='message') + { + // assume ISO-8859-1 if no charset specified + if (empty($o_part->charset)) + $o_part->charset = 'ISO-8859-1'; + + $body = rcube_charset_convert($body, $o_part->charset); + } + + fwrite($fp,$body); + return true; + + } + + + /** * Fetch message body of a specific message from the server * * @param int Message UID @@ -1372,7 +1424,7 @@ // make sure mailbox exists if (in_array($mailbox, $this->_list_mailboxes())) - $saved = iil_C_Append($this->conn, $mailbox, $message); + $saved = iil_C_AppendFromMixed($this->conn, $mailbox, $message); if ($saved) { diff -Naur roundcubemail-0.1/program/include/rcube_shared.inc roundcubemail-0.1.attach/program/include/rcube_shared.inc --- roundcubemail-0.1/program/include/rcube_shared.inc 2008-02-13 18:33:02.000000000 -0700 +++ roundcubemail-0.1.attach/program/include/rcube_shared.inc 2008-03-07 13:47:43.000000000 -0700 @@ -712,4 +712,128 @@ return $mime_type; } -?> \ No newline at end of file +function rc_msgstream( &$data, $function_name, $function_args, &$returns ) { + $stream_code = array( + 'count_size' => ' + $returns[0] += strlen($buf); + return true; + ', + + 'flatten' => ' + $returns[0] .= $buf; + return true; + ', + + 'fwrite' => ' + $local_fd = $function_args[0]; + + $bytes_written = fwrite($local_fd,$buf); + if ( $bytes_written === FALSE ) { + $returns[0] = PEAR::raiseError("error writing to file"); + return false; + } + + $returns[0] += $bytes_written; + return true; + ', + + 'imap_count_size' => ' + $returns[0] += strlen($buf); + return true; + ', + + 'imap_fputs' => ' + $local_fd = $function_args[0]; + + $bytes_written = fputs($local_fd,$buf); + if ( $bytes_written === FALSE ) { + $returns[0] = PEAR::raiseError("error writing to imap socket"); + return false; + } + + $returns[0] += $bytes_written; + return true; + ', + + 'smtp_send' => ' + $smtp = $function_args[0]; + + if (PEAR::isError($result = $smtp->_send($buf))) { + $returns[0] = $result; + return false; + } + return true; + ' + ); + + if ( !array_key_exists($function_name,$stream_code) ) { + return false; + } + + for ( $index=0; $index diff -Naur roundcubemail-0.1/program/include/rcube_smtp.inc roundcubemail-0.1.attach/program/include/rcube_smtp.inc --- roundcubemail-0.1/program/include/rcube_smtp.inc 2008-02-25 03:17:35.000000000 -0700 +++ roundcubemail-0.1.attach/program/include/rcube_smtp.inc 2008-03-07 13:47:43.000000000 -0700 @@ -183,13 +183,13 @@ // so preg_replace in SMTP_CONN->quotedata will store a reference instead of a copy. // We are still forced to make another copy here for a couple ticks so we don't really // get to save a copy in the method call. - $data = $text_headers . "\r\n" . $body; + $body[0] = $text_headers . "\r\n" . $body[0]; // unset old vars to save data and so we can pass into SMTP_CONN->data by reference. - unset($text_headers, $body); + unset($text_headers); // Send the message's headers and the body as SMTP data. - if (PEAR::isError($SMTP_CONN->data($data))) + if (PEAR::isError($SMTP_CONN->data($body))) { smtp_reset(); $response[] .= "Failed to send data"; diff -Naur roundcubemail-0.1/program/lib/Mail/mime.php roundcubemail-0.1.attach/program/lib/Mail/mime.php --- roundcubemail-0.1/program/lib/Mail/mime.php 2007-03-21 03:54:10.000000000 -0600 +++ roundcubemail-0.1.attach/program/lib/Mail/mime.php 2008-03-07 13:47:43.000000000 -0700 @@ -323,7 +323,7 @@ $encoding = 'base64', $disposition = 'attachment', $charset = '') { - $filedata = ($isfile === true) ? $this->_file2str($file) + $filedata = ($isfile === true) ? $this->_file2str_defer_read($file) : $file; if ($isfile === true) { // Force the name the user supplied, otherwise use $file @@ -387,6 +387,29 @@ } /** + * return an array description of a file for future opening + * + * @param string $file_name path of file to process + * @return array description of the file + * @access private + */ + function &_file2str_defer_read($file_name) + { + if (!is_readable($file_name)) { + $err = PEAR::raiseError('File is not readable ' . $file_name); + return $err; + } + if (!$fd = fopen($file_name, 'rb')) { + $err = PEAR::raiseError('Could not open ' . $file_name); + return $err; + } + $filesize = filesize($file_name); + fclose($fd); + + return array( "file", 'file_name' => $file_name, 'filesize' => $filesize ); + } + + /** * Adds a text subpart to the mimePart object and * returns it during the build process. * @@ -566,8 +589,9 @@ } $body = $this->get($build_params); $head = $this->txtHeaders($xtra_headers, $overwrite); - $mail = $head . $separation . $body; - return $mail; + + $body[0] = $head . $separation . $body[0]; + return $body; } diff -Naur roundcubemail-0.1/program/lib/Mail/mimePart.php roundcubemail-0.1.attach/program/lib/Mail/mimePart.php --- roundcubemail-0.1/program/lib/Mail/mimePart.php 2007-03-21 03:54:10.000000000 -0600 +++ roundcubemail-0.1.attach/program/lib/Mail/mimePart.php 2008-03-07 13:47:43.000000000 -0700 @@ -219,15 +219,64 @@ foreach ($tmp['headers'] as $key => $value) { $headers[] = $key . ': ' . $value; } - $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body']; + array_unshift( $tmp['body'], implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF ); + $subparts[] = $tmp['body']; } - $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF . - implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) . - '--' . $boundary.'--' . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF; + // Add boundaries to subparts, build an array of strings and/or file descriptions, + // consolidate strings where possible + $body_parts = array( '' ); + foreach ( $subparts as $part ) { + $this_part = '--' . $boundary . MAIL_MIMEPART_CRLF ; + + if ( ! is_array($part) ) { + $this_part .= $part; + } else { + foreach ( $part as $item ) { + if ( is_string($item) ) { + $this_part .= $item; + } + + if ( is_array($item) ) { + if ( $this_part != "" ) { + if ( is_array( $body_parts[count($body_parts)-1] ) ) { + array_push( $body_parts, $this_part ); + } else { + $body_parts[count($body_parts)-1] .= $this_part; + } + } + $this_part = ""; + array_push( $body_parts, $item ); + } + } + } + + if ( $this_part != "" ) { + if ( is_array( $body_parts[count($body_parts)-1] ) ) { + array_push( $body_parts, $this_part ); + } else { + $body_parts[count($body_parts)-1] .= $this_part; + } + } + + } + + // Add the terminator + $this_part = '--' . $boundary.'--' . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF; + if ( is_array( $body_parts[count($body_parts)-1] ) ) { + array_push( $body_parts, $this_part ); + } else { + $body_parts[count($body_parts)-1] .= $this_part; + } + + $encoded['body'] = $body_parts; } else { - $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF; + if ( is_array($this->_body) ) { + $encoded['body'] = array( $this->_body ); + } else { + $encoded['body'] = array( $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF ); + } } // Add headers to $encoded diff -Naur roundcubemail-0.1/program/lib/Net/SMTP.php roundcubemail-0.1.attach/program/lib/Net/SMTP.php --- roundcubemail-0.1/program/lib/Net/SMTP.php 2008-01-29 12:30:48.000000000 -0700 +++ roundcubemail-0.1.attach/program/lib/Net/SMTP.php 2008-03-07 13:47:43.000000000 -0700 @@ -783,14 +783,29 @@ */ function quotedata(&$data) { - /* Change Unix (\n) and Mac (\r) linefeeds into - * Internet-standard CRLF (\r\n) linefeeds. */ - $data = preg_replace(array('/(?_esmtp['SIZE']) && ($this->_esmtp['SIZE'] > 0)) { - if (strlen($data) >= $this->_esmtp['SIZE']) { + $returns = array(0); + $result = rc_msgstream($data,'count_size',array(),$returns); + if ( !$result ) { + if ( PEAR::isError($returns[0]) ) { + return $returns[0]; + } else { + return PEAR::raiseError("error while determining message size"); + } + } + $size = $returns[0]; + + if ($size >= $this->_esmtp['SIZE']) { $this->disconnect(); return PEAR::raiseError('Message size excedes the server limit'); } @@ -826,8 +852,20 @@ if (PEAR::isError($error = $this->_parseResponse(354))) { return $error; } + + // send the data + $returns = array(0); + $result = rc_msgstream($data,'smtp_send',array(&$this),$returns); + if ( !$result ) { + if ( PEAR::isError($returns[0]) ) { + return $returns[0]; + } else { + return PEAR::raiseError("error while sending message data"); + } + } - if (PEAR::isError($result = $this->_send($data . "\r\n.\r\n"))) { + //send data terminator + if (PEAR::isError($result = $this->_send("\r\n.\r\n"))) { return $result; } if (PEAR::isError($error = $this->_parseResponse(250))) { diff -Naur roundcubemail-0.1/program/lib/imap.inc roundcubemail-0.1.attach/program/lib/imap.inc --- roundcubemail-0.1/program/lib/imap.inc 2008-02-17 11:29:50.000000000 -0700 +++ roundcubemail-0.1.attach/program/lib/imap.inc 2008-03-07 14:31:19.000000000 -0700 @@ -1957,10 +1957,9 @@ function iil_C_CountUnseen(&$conn, $folder) { $index = iil_C_Search($conn, $folder, 'ALL UNSEEN'); if (is_array($index)) { - $str = implode(',', $index); - if (empty($str)) { - return false; - } + if (count($index)==0 or count($index)==1 and $index[0] == "" ) { + return false; + } return count($index); } return false; @@ -2296,18 +2295,23 @@ } -function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode) { +function iil_C_HandlePartBody(&$conn, $mailbox, $id, $part, $mode, $body_fp=NULL) { /* modes: 1: return string 2: print 3: base64 and print + 4: base64 and write to fp */ $fp = $conn->fp; $result = false; if (($part == 0) || empty($part)) { $part = 'TEXT'; } - + + if ($mode == 4 and $body_fp == NULL ) { + return false; + } + if (iil_C_Select($conn, $mailbox)) { $reply_key = '* ' . $id; @@ -2336,6 +2340,8 @@ echo substr($line, $from, $len); } else if ($mode == 3) { echo base64_decode(substr($line, $from, $len)); + } else if ($mode == 4) { + fwrite($body_fp, base64_decode(substr($line, $from, $len))); } }else if ($line[$len-1] == '}') { //multi-line request, find sizes of content and receive that many bytes @@ -2349,7 +2355,7 @@ $remaining = $bytes - $received; $line = iil_ReadLine($fp, 1024); $len = strlen($line); - + if ($len > $remaining) { $line = substr($line, 0, $remaining); } @@ -2360,6 +2366,8 @@ echo chop($line) . "\n"; flush(); } else if ($mode == 3) { echo base64_decode($line); flush(); + } else if ($mode == 4) { + fwrite($body_fp, base64_decode($line)); } } } @@ -2368,6 +2376,10 @@ $line = iil_ReadLine($fp, 1024); } while (!iil_StartsWith($line, $key)); + if ($mode == 4) { + return true; + } + if ($result) { $result = chop($result); return $result; // substr($result, 0, strlen($result)-1); @@ -2395,6 +2407,10 @@ iil_C_HandlePartBody($conn, $mailbox, $id, $part, 3); } +function iil_C_WriteBase64BodyToFP(&$conn, $mailbox, $id, $part, $fp) { + iil_C_HandlePartBody($conn, $mailbox, $id, $part, 4, $fp); +} + function iil_C_CreateFolder(&$conn, $folder) { $fp = $conn->fp; if (fputs($fp, 'c CREATE "' . $folder . '"' . "\r\n")) { @@ -2519,6 +2535,70 @@ } +function iil_C_AppendFromMixed(&$conn, $folder, &$data){ + if (!$folder) return false; + + if ( !is_array($data) ) { + return iil_C_Append($conn,$folder,$data); + } + + //determine the message size + $returns = array(0); + $result = rc_msgstream($data,'imap_count_size',array(),$returns); + if ( !$result ) { + if ( PEAR::isError($returns[0]) ) { + $conn->error .= $returns[0]->toString()."\n"; + } else { + $conn->error .= "error while determining message size\n"; + } + return false; + } + $msg_size = $returns[0]; + + $fp = $conn->fp; + $len = $msg_size; + if (!$len) return false; + + //send APPEND command + $request = 'A APPEND "' . $folder . '" (\\Seen) {' . $len . "}\r\n"; + $bytes_sent = 0; + if (fputs($fp, $request)){ + $line=iil_ReadLine($fp, 100); + + // send data + $returns = array(0); + $result = rc_msgstream($data,'imap_fputs',array($fp),$returns); + if ( !$result ) { + if ( PEAR::isError($returns[0]) ) { + $conn->error .= $returns[0]->toString()."\n"; + } else { + $conn->error .= "error while writing to imap socket\n"; + } + return false; + } + $bytes_sent = $returns[0]; + + fputs($fp, "\r\n"); + flush(); + + //read response + do{ + $line=iil_ReadLine($fp, 1000); + }while ($line[0] != 'A'); + + $result = (iil_ParseResult($line)==0); + if (!$result) { + $conn->error .= $line . "\n"; + } + return $result; + + }else{ + $conn->error .= "Couldn't send command \"$request\"\n"; + return false; + } +} + + function iil_C_FetchStructureString(&$conn, $folder, $id) { $fp = $conn->fp; $result = false; diff -Naur roundcubemail-0.1/program/steps/mail/compose.inc roundcubemail-0.1.attach/program/steps/mail/compose.inc --- roundcubemail-0.1/program/steps/mail/compose.inc 2008-02-11 10:39:31.000000000 -0700 +++ roundcubemail-0.1.attach/program/steps/mail/compose.inc 2008-03-07 13:47:56.000000000 -0700 @@ -594,7 +594,8 @@ $tmp_path = tempnam($temp_dir, 'rcmAttmnt'); if ($fp = fopen($tmp_path, 'w')) { - fwrite($fp, $IMAP->get_message_part($message['UID'], $pid, $part->encoding)); + //HERE + $IMAP->write_message_part_to_fp($fp, $message['UID'], $pid, $part->encoding); fclose($fp); $_SESSION['compose']['attachments'][] = array( diff -Naur roundcubemail-0.1/program/steps/mail/func.inc roundcubemail-0.1.attach/program/steps/mail/func.inc --- roundcubemail-0.1/program/steps/mail/func.inc 2008-02-20 15:47:06.000000000 -0700 +++ roundcubemail-0.1.attach/program/steps/mail/func.inc 2008-03-07 13:47:43.000000000 -0700 @@ -1419,21 +1419,56 @@ // send mail using PHP's mail() function else - { - // unset some headers because they will be added by the mail() function - $headers_enc = $message->headers($headers); - $headers_php = $message->_headers; - unset($headers_php['To'], $headers_php['Subject']); - - // reset stored headers and overwrite - $message->_headers = array(); - $header_str = $message->txtHeaders($headers_php); - - if (ini_get('safe_mode')) - $sent = mail($headers_enc['To'], $headers_enc['Subject'], $msg_body, $header_str); - else - $sent = mail($headers_enc['To'], $headers_enc['Subject'], $msg_body, $header_str, "-f$from"); + { + $sendmail_path = ini_get('sendmail_path'); + if ( preg_match('/^[^ ]+\/sendmail /', $sendmail_path) ) { + //for systems with sendmail + + $header_str = $message->txtHeaders($headers); + + // add headers to message body before sending + $msg_body[0] = $header_str . "\r\n" . $msg_body[0]; + + $sent = rcmail_mail_replacement( $msg_body, $from ); + } else { + /** + * for systems without sendmail (?) + * + * this will only work if there is enough memory availble to store the entire encoded + * message + */ + + // unset some headers because they will be added by the mail() function + $headers_enc = $message->headers($headers); + $headers_php = $message->_headers; + unset($headers_php['To'], $headers_php['Subject']); + + // reset stored headers and overwrite + $message->_headers = array(); + $header_str = $message->txtHeaders($headers_php); + + $returns = array(""); + $result = rc_msgstream( $msg_body, 'flatten', array(), $returns); + $msg_body_str = &$returns[0]; + + // error writing data to sendmail + if ( !$result ) { + if ( PEAR::isError($returns[0]) ) { + write_log("errors","error while assembling message, ".$returns[0]->toString() ); + } else { + write_log("errors","error while assembling message" ); + } + $sent = false; + } else { + if (ini_get('safe_mode')) + $sent = mail($headers_enc['To'], $headers_enc['Subject'], $msg_body_str, $header_str); + else + $sent = mail($headers_enc['To'], $headers_enc['Subject'], $msg_body_str, $header_str, "-f$from"); + } + + unset($msg_body_str,$returns); } + } if ($sent) // remove MDN headers after sending unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']); @@ -1445,6 +1480,60 @@ } +function rcmail_mail_replacement( &$msg_body, $from ) { + $desc = array( + 0 => array("pipe", "r"), + 1 => array("pipe", "w"), + ); + + $sendmail_cmd = ini_get('sendmail_path'); + if (!ini_get('safe_mode')) { + $sendmail_cmd .= " -f".escapeshellarg($from); + } + + $sendmail_proc = proc_open($sendmail_cmd, $desc, $sendmail_fd ); + + if ( is_resource($sendmail_proc) ) { + // write msg_body to sendmail's stdin + $returns = array( 0 ); + $result = rc_msgstream( $msg_body, 'fwrite', array($sendmail_fd[0]), $returns); + fclose($sendmail_fd[0]); + + // read output from sendmail + $sendmail_out = ""; + while ( $buf = fread($sendmail_fd[1],4096) ) { + $sendmail_out .= $buf; + } + fclose($sendmail_fd[1]); + + // wait for sendmail to close + $return_value = proc_close($sendmail_proc); + + // error writing data to sendmail + if ( !$result ) { + if ( PEAR::isError($returns[0]) ) { + write_log("errors","rcmail_mail_replacement: error writing data to '$sendmail_cmd', ".$returns[0]->toString() ); + } else { + write_log("errors","rcmail_mail_replacement: error writing data to '$sendmail_cmd'"); + } + return false; + } + + if ( !$return_value ) { + // sendmail success + return true; + } else { + // sendmail failure + write_log("errors","rcmail_mail_replacement: sendmail error (returns $return_value):\n$sendmail_out"); + return false; + } + } else { + write_log("errors","rcmail_mail_replacement: could not open '$sendmail_cmd'"); + return false; + } +} + + function rcmail_send_mdn($uid) { global $CONFIG, $USER, $IMAP;