diff -upN sites/all/modules/mimemail-head/LICENSE.txt sites/all/modules/mimemail/LICENSE.txt --- sites/all/modules/mimemail-head/LICENSE.txt 2006-04-23 02:54:26.000000000 -0700 +++ sites/all/modules/mimemail/LICENSE.txt 1969-12-31 16:00:00.000000000 -0800 @@ -1,274 +0,0 @@ -GNU GENERAL PUBLIC LICENSE - - Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, -Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute -verbatim copies of this license document, but changing it is not allowed. - - Preamble - -The licenses for most software are designed to take away your freedom to -share and change it. By contrast, the GNU General Public License is -intended to guarantee your freedom to share and change free software--to -make sure the software is free for all its users. This General Public License -applies to most of the Free Software Foundation's software and to any other -program whose authors commit to using it. (Some other Free Software -Foundation software is covered by the GNU Library General Public License -instead.) You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our -General Public Licenses are designed to make sure that you have the -freedom to distribute copies of free software (and charge for this service if -you wish), that you receive source code or can get it if you want it, that you -can change the software or use pieces of it in new free programs; and that -you know you can do these things. - -To protect your rights, we need to make restrictions that forbid anyone to -deny you these rights or to ask you to surrender the rights. These restrictions -translate to certain responsibilities for you if you distribute copies of the -software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis or for -a fee, you must give the recipients all the rights that you have. You must make -sure that they, too, receive or can get the source code. And you must show -them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and (2) -offer you this license which gives you legal permission to copy, distribute -and/or modify the software. - -Also, for each author's protection and ours, we want to make certain that -everyone understands that there is no warranty for this free software. If the -software is modified by someone else and passed on, we want its recipients -to know that what they have is not the original, so that any problems -introduced by others will not reflect on the original authors' reputations. - -Finally, any free program is threatened constantly by software patents. We -wish to avoid the danger that redistributors of a free program will individually -obtain patent licenses, in effect making the program proprietary. To prevent -this, we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - -The precise terms and conditions for copying, distribution and modification -follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND - MODIFICATION - -0. This License applies to any program or other work which contains a notice -placed by the copyright holder saying it may be distributed under the terms -of this General Public License. The "Program", below, refers to any such -program or work, and a "work based on the Program" means either the -Program or any derivative work under copyright law: that is to say, a work -containing the Program or a portion of it, either verbatim or with -modifications and/or translated into another language. (Hereinafter, translation -is included without limitation in the term "modification".) Each licensee is -addressed as "you". - -Activities other than copying, distribution and modification are not covered -by this License; they are outside its scope. The act of running the Program is -not restricted, and the output from the Program is covered only if its contents -constitute a work based on the Program (independent of having been made -by running the Program). Whether that is true depends on what the Program -does. - -1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this License -and to the absence of any warranty; and give any other recipients of the -Program a copy of this License along with the Program. - -You may charge a fee for the physical act of transferring a copy, and you -may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of it, -thus forming a work based on the Program, and copy and distribute such -modifications or work under the terms of Section 1 above, provided that you -also meet all of these conditions: - -a) You must cause the modified files to carry prominent notices stating that -you changed the files and the date of any change. - -b) You must cause any work that you distribute or publish, that in whole or in -part contains or is derived from the Program or any part thereof, to be -licensed as a whole at no charge to all third parties under the terms of this -License. - -c) If the modified program normally reads commands interactively when run, -you must cause it, when started running for such interactive use in the most -ordinary way, to print or display an announcement including an appropriate -copyright notice and a notice that there is no warranty (or else, saying that -you provide a warranty) and that users may redistribute the program under -these conditions, and telling the user how to view a copy of this License. -(Exception: if the Program itself is interactive but does not normally print such -an announcement, your work based on the Program is not required to print -an announcement.) - -These requirements apply to the modified work as a whole. If identifiable -sections of that work are not derived from the Program, and can be -reasonably considered independent and separate works in themselves, then -this License, and its terms, do not apply to those sections when you distribute -them as separate works. But when you distribute the same sections as part -of a whole which is a work based on the Program, the distribution of the -whole must be on the terms of this License, whose permissions for other -licensees extend to the entire whole, and thus to each and every part -regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest your rights to -work written entirely by you; rather, the intent is to exercise the right to -control the distribution of derivative or collective works based on the -Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of a -storage or distribution medium does not bring the other work under the scope -of this License. - -3. You may copy and distribute the Program (or a work based on it, under -Section 2) in object code or executable form under the terms of Sections 1 -and 2 above provided that you also do one of the following: - -a) Accompany it with the complete corresponding machine-readable source -code, which must be distributed under the terms of Sections 1 and 2 above -on a medium customarily used for software interchange; or, - -b) Accompany it with a written offer, valid for at least three years, to give -any third party, for a charge no more than your cost of physically performing -source distribution, a complete machine-readable copy of the corresponding -source code, to be distributed under the terms of Sections 1 and 2 above on -a medium customarily used for software interchange; or, - -c) Accompany it with the information you received as to the offer to distribute -corresponding source code. (This alternative is allowed only for -noncommercial distribution and only if you received the program in object -code or executable form with such an offer, in accord with Subsection b -above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source code -means all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation and -installation of the executable. However, as a special exception, the source -code distributed need not include anything that is normally distributed (in -either source or binary form) with the major components (compiler, kernel, -and so on) of the operating system on which the executable runs, unless that -component itself accompanies the executable. - -If distribution of executable or object code is made by offering access to -copy from a designated place, then offering equivalent access to copy the -source code from the same place counts as distribution of the source code, -even though third parties are not compelled to copy the source along with the -object code. - -4. You may not copy, modify, sublicense, or distribute the Program except as -expressly provided under this License. Any attempt otherwise to copy, -modify, sublicense or distribute the Program is void, and will automatically -terminate your rights under this License. However, parties who have received -copies, or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - -5. You are not required to accept this License, since you have not signed it. -However, nothing else grants you permission to modify or distribute the -Program or its derivative works. These actions are prohibited by law if you -do not accept this License. Therefore, by modifying or distributing the -Program (or any work based on the Program), you indicate your acceptance -of this License to do so, and all its terms and conditions for copying, -distributing or modifying the Program or works based on it. - -6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the original -licensor to copy, distribute or modify the Program subject to these terms and -conditions. You may not impose any further restrictions on the recipients' -exercise of the rights granted herein. You are not responsible for enforcing -compliance by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), conditions -are imposed on you (whether by court order, agreement or otherwise) that -contradict the conditions of this License, they do not excuse you from the -conditions of this License. If you cannot distribute so as to satisfy -simultaneously your obligations under this License and any other pertinent -obligations, then as a consequence you may not distribute the Program at all. -For example, if a patent license would not permit royalty-free redistribution -of the Program by all those who receive copies directly or indirectly through -you, then the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply and -the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any patents or -other property right claims or to contest validity of any such claims; this -section has the sole purpose of protecting the integrity of the free software -distribution system, which is implemented by public license practices. Many -people have made generous contributions to the wide range of software -distributed through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing to -distribute software through any other system and a licensee cannot impose -that choice. - -This section is intended to make thoroughly clear what is believed to be a -consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in certain -countries either by patents or by copyrighted interfaces, the original copyright -holder who places the Program under this License may add an explicit -geographical distribution limitation excluding those countries, so that -distribution is permitted only in or among countries not thus excluded. In such -case, this License incorporates the limitation as if written in the body of this -License. - -9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will be -similar in spirit to the present version, but may differ in detail to address new -problems or concerns. - -Each version is given a distinguishing version number. If the Program specifies -a version number of this License which applies to it and "any later version", -you have the option of following the terms and conditions either of that -version or of any later version published by the Free Software Foundation. If -the Program does not specify a version number of this License, you may -choose any version ever published by the Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free programs -whose distribution conditions are different, write to the author to ask for -permission. For software which is copyrighted by the Free Software -Foundation, write to the Free Software Foundation; we sometimes make -exceptions for this. Our decision will be guided by the two goals of -preserving the free status of all derivatives of our free software and of -promoting the sharing and reuse of software generally. - - NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, -THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT -PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE -STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT -WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND -PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL -NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR -AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR -ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE -LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, -SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES -ARISING OUT OF THE USE OR INABILITY TO USE THE -PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA -OR DATA BEING RENDERED INACCURATE OR LOSSES -SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE -PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN -IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF -THE POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS diff -upN sites/all/modules/mimemail-head/README.txt sites/all/modules/mimemail/README.txt --- sites/all/modules/mimemail-head/README.txt 2005-11-16 18:56:38.000000000 -0800 +++ sites/all/modules/mimemail/README.txt 2008-09-05 14:02:43.000000000 -0700 @@ -1,4 +1,4 @@ -$Id: README.txt,v 1.1 2005/11/17 02:56:38 vauxia Exp $ +$Id$ INSTALLATION Hopefully, you know the drill by now :) diff -upN sites/all/modules/mimemail-head/html_to_text.inc sites/all/modules/mimemail/html_to_text.inc --- sites/all/modules/mimemail-head/html_to_text.inc 1969-12-31 16:00:00.000000000 -0800 +++ sites/all/modules/mimemail/html_to_text.inc 2008-09-11 09:59:28.000000000 -0700 @@ -0,0 +1,369 @@ +' characters are repeated on + * subsequent wrapped lines. Others are replaced by spaces. + */ +function mimemail_wrap_mail($text, $indent = '') { + // Convert CRLF into LF. + $text = str_replace("\r", '', $text); + // See if soft-wrapping is allowed. + $clean_indent = _mimemail_html_to_text_clean($indent); + $soft = strpos($clean_indent, ' ') === FALSE; + // Check if the string has line breaks. + if (strpos($text, "\n") !== FALSE) { + // Remove trailing spaces to make existing breaks hard. + $text = preg_replace('/ +\n/m', "\n", $text); + // Wrap each line at the needed width. + $lines = explode("\n", $text); + array_walk($lines, '_mimemail_wrap_mail_line', array('soft' => $soft, 'length' => strlen($indent))); + $text = implode("\n", $lines); + } + else { + // Wrap this line. + _mimemail_wrap_mail_line($text, 0, array('soft' => $soft, 'length' => strlen($indent))); + } + // Empty lines with nothing but spaces. + $text = preg_replace('/^ +\n/m', "\n", $text); + // Space-stuff special lines. + $text = preg_replace('/^(>| |From)/m', ' $1', $text); + // Apply indentation. We only include non-'>' indentation on the first line. + $text = $indent . substr(preg_replace('/^/m', $clean_indent, $text), strlen($indent)); + + return $text; +} + +/** + * Transform an HTML string into plain text, preserving the structure of the + * markup. Useful for preparing the body of a node to be sent by e-mail. + * + * The output will be suitable for use as 'format=flowed; delsp=yes' text + * (RFC 3676) and can be passed directly to mimemail_mail() for sending. + * + * We deliberately use LF rather than CRLF, see mimemail_mail(). + * + * This function provides suitable alternatives for the following tags: + *

    1. + *


      + * + * @param $string + * The string to be transformed. + * @param $allowed_tags (optional) + * If supplied, a list of tags that will be transformed. If omitted, all + * all supported tags are transformed. + * @return + * The transformed string. + */ +function mimemail_html_to_text($string, $allowed_tags = NULL) { + // Cache list of supported tags. + static $supported_tags; + if (empty($supported_tags)) { + $supported_tags = array('a', 'em', 'i', 'strong', 'b', 'br', 'p', 'blockquote', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr'); + } + + // Make sure only supported tags are kept. + $allowed_tags = isset($allowed_tags) ? array_intersect($supported_tags, $allowed_tags) : $supported_tags; + + // Make sure tags, entities and attributes are well-formed and properly nested. + $string = _mimemail_filter_htmlcorrector(filter_xss($string, $allowed_tags)); + + // Apply inline styles. + $string = preg_replace('!!i', '/', $string); + $string = preg_replace('!!i', '*', $string); + + // Replace inline
      tags with the text of link and a footnote. + // 'See the Drupal site' becomes + // 'See the Drupal site [1]' with the URL included as a footnote. + _mimemail_html_to_mail_urls(NULL, TRUE); + $pattern = '@(]+?href="([^"]*)"[^>]*?>(.+?))@i'; + $string = preg_replace_callback($pattern, '_mimemail_html_to_mail_urls', $string); + $urls = _mimemail_html_to_mail_urls(); + $footnotes = ''; + if (count($urls)) { + $footnotes .= "\n"; + for ($i = 0, $max = count($urls); $i < $max; $i++) { + $footnotes .= '['. ($i + 1) .'] '. $urls[$i] ."\n"; + } + } + + // Split tags from text. + $split = preg_split('/<([^>]+?)>/', $string, -1, PREG_SPLIT_DELIM_CAPTURE); + // Note: PHP ensures the array consists of alternating delimiters and literals + // and begins and ends with a literal (inserting $null as required). + + $tag = FALSE; // Odd/even counter (tag or no tag) + $casing = NULL; // Case conversion function + $output = ''; + $indent = array(); // All current indentation string chunks + $lists = array(); // Array of counters for opened lists + foreach ($split as $value) { + $chunk = NULL; // Holds a string ready to be formatted and output. + + // Process HTML tags (but don't output any literally). + if ($tag) { + list($tagname) = explode(' ', strtolower($value), 2); + switch ($tagname) { + // List counters + case 'ul': + array_unshift($lists, '*'); + break; + case 'ol': + array_unshift($lists, 1); + break; + case '/ul': + case '/ol': + array_shift($lists); + $chunk = ''; // Ensure blank new-line. + break; + + // Quotation/list markers, non-fancy headers + case 'blockquote': + // Format=flowed indentation cannot be mixed with lists. + $indent[] = count($lists) ? ' "' : '>'; + break; + case 'li': + $indent[] = is_numeric($lists[0]) ? ' '. $lists[0]++ .') ' : ' * '; + break; + case 'dd': + $indent[] = ' '; + break; + case 'h3': + $indent[] = '.... '; + break; + case 'h4': + $indent[] = '.. '; + break; + case '/blockquote': + if (count($lists)) { + // Append closing quote for inline quotes (immediately). + $output = rtrim($output, "> \n") ."\"\n"; + $chunk = ''; // Ensure blank new-line. + } + // Fall-through + case '/li': + case '/dd': + array_pop($indent); + break; + case '/h3': + case '/h4': + array_pop($indent); + case '/h5': + case '/h6': + $chunk = ''; // Ensure blank new-line. + break; + + // Fancy headers + case 'h1': + $indent[] = '======== '; + $casing = 'drupal_strtoupper'; + break; + case 'h2': + $indent[] = '-------- '; + $casing = 'drupal_strtoupper'; + break; + case '/h1': + case '/h2': + $casing = NULL; + // Pad the line with dashes. + $output = _mimemail_html_to_text_pad($output, ($tagname == '/h1') ? '=' : '-', ' '); + array_pop($indent); + $chunk = ''; // Ensure blank new-line. + break; + + // Horizontal rulers + case 'hr': + // Insert immediately. + $output .= mimemail_wrap_mail('', implode('', $indent)) ."\n"; + $output = _mimemail_html_to_text_pad($output, '-'); + break; + + // Paragraphs and definition lists + case '/p': + case '/dl': + $chunk = ''; // Ensure blank new-line. + break; + } + } + // Process blocks of text. + else { + // Convert inline HTML text to plain text. + $value = trim(preg_replace('/\s+/', ' ', decode_entities($value))); + if (strlen($value)) { + $chunk = $value; + } + } + + // See if there is something waiting to be output. + if (isset($chunk)) { + // Apply any necessary case conversion. + if (isset($casing)) { + $chunk = $casing($chunk); + } + // Format it and apply the current indentation. + $output .= mimemail_wrap_mail($chunk, implode('', $indent)) ."\n"; + // Remove non-quotation markers from indentation. + $indent = array_map('_mimemail_html_to_text_clean', $indent); + } + + $tag = !$tag; + } + + return $output . $footnotes; +} + +/** + * Helper function for array_walk in mimemail_wrap_mail(). + * + * Wraps words on a single line. + */ +function _mimemail_wrap_mail_line(&$line, $key, $values) { + // Use soft-breaks only for purely quoted or unindented text. + $line = wordwrap($line, 77 - $values['length'], $values['soft'] ? " \n" : "\n"); + // Break really long words at the maximum width allowed. + $line = wordwrap($line, 996 - $values['length'], $values['soft'] ? " \n" : "\n"); +} + +/** + * Helper function for mimemail_html_to_text(). + * + * Keeps track of URLs and replaces them with placeholder tokens. + */ +function _mimemail_html_to_mail_urls($match = NULL, $reset = FALSE) { + global $base_url, $base_path; + static $urls = array(), $regexp; + + if ($reset) { + // Reset internal URL list. + $urls = array(); + } + else { + if (empty($regexp)) { + $regexp = '@^'. preg_quote($base_path, '@') .'@'; + } + if ($match) { + list(, , $url, $label) = $match; + // Ensure all URLs are absolute. + $urls[] = strpos($url, '://') ? $url : preg_replace($regexp, $base_url .'/', $url); + return $label .' ['. count($urls) .']'; + } + } + return $urls; +} + +/** + * Helper function for mimemail_wrap_mail() and mimemail_html_to_text(). + * + * Replace all non-quotation markers from a given piece of indentation with spaces. + */ +function _mimemail_html_to_text_clean($indent) { + return preg_replace('/[^>]/', ' ', $indent); +} + +/** + * Helper function for mimemail_html_to_text(). + * + * Pad the last line with the given character. + */ +function _mimemail_html_to_text_pad($text, $pad, $prefix = '') { + // Remove last line break. + $text = substr($text, 0, -1); + // Calculate needed padding space and add it. + if (($p = strrpos($text, "\n")) === FALSE) { + $p = -1; + } + $n = max(0, 79 - (strlen($text) - $p)); + // Add prefix and padding, and restore linebreak. + return $text . $prefix . str_repeat($pad, $n - strlen($prefix)) ."\n"; +} + +/** + * Scan input and make sure that all HTML tags are properly closed and nested. + * + * Copied from,Drupal 6 filter.module. + */ +function _mimemail_filter_htmlcorrector($text) { + // Prepare tag lists. + static $no_nesting, $single_use; + if (!isset($no_nesting)) { + // Tags which cannot be nested but are typically left unclosed. + $no_nesting = drupal_map_assoc(array('li', 'p')); + + // Single use tags in HTML4 + $single_use = drupal_map_assoc(array('base', 'meta', 'link', 'hr', 'br', 'param', 'img', 'area', 'input', 'col', 'frame')); + } + + // Properly entify angles. + $text = preg_replace('!<([^a-zA-Z/])!', '<\1', $text); + + // Split tags from text. + $split = preg_split('/<([^>]+?)>/', $text, -1, PREG_SPLIT_DELIM_CAPTURE); + // Note: PHP ensures the array consists of alternating delimiters and literals + // and begins and ends with a literal (inserting $null as required). + + $tag = false; // Odd/even counter. Tag or no tag. + $stack = array(); + $output = ''; + foreach ($split as $value) { + // Process HTML tags. + if ($tag) { + list($tagname) = explode(' ', strtolower($value), 2); + // Closing tag + if ($tagname{0} == '/') { + $tagname = substr($tagname, 1); + // Discard XHTML closing tags for single use tags. + if (!isset($single_use[$tagname])) { + // See if we possibly have a matching opening tag on the stack. + if (in_array($tagname, $stack)) { + // Close other tags lingering first. + do { + $output .= ''; + } while (array_shift($stack) != $tagname); + } + // Otherwise, discard it. + } + } + // Opening tag + else { + // See if we have an identical 'no nesting' tag already open and close it if found. + if (count($stack) && ($stack[0] == $tagname) && isset($no_nesting[$stack[0]])) { + $output .= ''; + } + // Push non-single-use tags onto the stack + if (!isset($single_use[$tagname])) { + array_unshift($stack, $tagname); + } + // Add trailing slash to single-use tags as per X(HT)ML. + else { + $value = rtrim($value, ' /') .' /'; + } + $output .= '<'. $value .'>'; + } + } + else { + // Passthrough all text. + $output .= $value; + } + $tag = !$tag; + } + // Close remaining tags. + while (count($stack) > 0) { + $output .= ''; + } + return $output; +} diff -upN sites/all/modules/mimemail-head/mimemail.inc sites/all/modules/mimemail/mimemail.inc --- sites/all/modules/mimemail-head/mimemail.inc 2008-02-17 16:43:36.000000000 -0800 +++ sites/all/modules/mimemail/mimemail.inc 2008-09-11 10:03:35.000000000 -0700 @@ -1,17 +1,19 @@ */ +include drupal_get_path('module', 'mimemail') . '/html_to_text.inc'; + /** * Attempts to RFC822-compliant headers for the mail message or its MIME parts - * TODO could use some enhancement and stress testing - * + * TODO could use some enhancement and stress testing + * * @param $headers An array of headers * @return header string */ @@ -22,15 +24,15 @@ function mimemail_rfc_headers($headers) $key = trim($key); // collapse spaces and get rid of newline characters $value = preg_replace('/(\s+|\n|\r|^\s|\s$)/', ' ', $value); - + //fold headers if they're too long if (strlen($value) > 60) { //if there's a semicolon, use that to separate if (count($array = preg_split('/;\s*/', $value)) > 1) { $value = trim(join(";$crlf ", $array)); - } + } else { - $value = wordwrap($value, 50, "$crlf ", false); + $value = wordwrap($value, 50, "$crlf ", FALSE); } } $header .= "$key: $value$crlf"; @@ -44,7 +46,7 @@ function mimemail_rfc_headers($headers) * @param $headers An array of headers * @return header string. */ -function mimemail_headers($headers, $from='') { +function mimemail_headers($headers, $from = '') { // Note: This may not work. The MTA may rewrite the Return-Path, and Errors-To is deprecated. if (!$from) { $from = variable_get('site_mail', ini_get('sendmail_from')); @@ -54,45 +56,13 @@ function mimemail_headers($headers, $fro // allow a mail to overwrite standard headers. $headers = array_merge(array('Return-Path' => "<$from_email>", 'Errors-To' => $from, 'From' => $from, 'Content-Type' => 'text/plain; charset=utf-8; format=flowed'), $headers); - return $headers; -} - -/** - * Converts html to utf-8 encoded text. - * - * @param $txt html text that needs formatting. - * @param $inline Optional. If TRUE put links in the text, - * if FALSE put a footnote into the text and - * a list of links below it. Default: FALSE - * - * @return formatted text encoded in utf-8 - */ -function mimemail_html_to_text($txt, $inline = FALSE) { - $pattern = '@(]*>(.+?))@emi'; - if ($inline) { - $txt = preg_replace($pattern, "_mimemail_uri('\\2', '\\3')", $txt); - } - else { - $txt = preg_replace($pattern, "'\\3 ['. _mimemail_urls('\\2') .']'", $txt); - $urls = _mimemail_urls(); - if (count($urls)) { - $txt .= "\n"; - $i = 0; - for ($max = count($urls); $i < $max; $i++) { - $url = preg_replace('/^mailto:(.+@.+)(\?.*)?/', '\1', $urls[$i]); - $txt .= '['. ($i + 1) .'] '. $url ."\n"; - } - } - _mimemail_urls(0, TRUE); + // Run all headers through mime_header_encode() to convert non-ascii + // characters to an rfc compliant string, similar to drupal_mail(). + foreach($headers as $key => $value) { + $headers[$key] = mime_header_encode($value); } - // some basic html to text conversion - $replace = _mimemail_html2text(); - $txt = preg_replace(array_keys($replace), $replace, $txt); - $txt = preg_replace("/\n\s+\n/", "\n\n", $txt); - $txt = strip_tags($txt); - $txt = decode_entities($txt); - return wordwrap($txt, 80); + return $headers; } /** @@ -110,7 +80,7 @@ function mimemail_html_to_text($txt, $in * 'name' => file name, * 'file' => reference to local file, * 'Content-ID' => generated Content-ID, - * 'Content-Type' => derived using mime_content_type + * 'Content-Type' => derived using mime_content_type * if available, educated guess otherwise * ) * ) @@ -118,15 +88,15 @@ function mimemail_html_to_text($txt, $in function mimemail_extract_files($html) { $pattern = '/(]+href="?|]+codebase="?|@import |src="?)\/?([^"]+)("?)/emis'; $html = preg_replace($pattern, '"\\1". _mimemail_file("\\2") ."\\3"', $html); - + $document = array(array( 'Content-Type' => "text/html; charset=utf-8", 'Content-Transfer-Encoding' => 'base64', 'content' => chunk_split(base64_encode($html)), )); - + $files = _mimemail_file(); - + return array_merge($document, $files); } @@ -137,13 +107,17 @@ function mimemail_extract_files($html) { * * @return an absolute : */ -function _mimemail_file($file = NULL, $type = '', $disposition = 'related') { +function _mimemail_file($file = NULL, $name = '', $type = '', $disposition = 'related') { static $files = array(); if ($file && !preg_match('@://|mailto:@', $file) && file_exists($file)) { $content_id = md5($file) .'@'. $_SERVER['HTTP_HOST']; - $new_file = array('name' => substr($file, strrpos($file, '/') + 1), + if (!$name) { + $name = substr($file, strrpos($file, '/') + 1); + } + + $new_file = array('name' => $name, 'file' => $file, 'Content-ID' => $content_id, 'Content-Disposition' => $disposition, @@ -154,11 +128,11 @@ function _mimemail_file($file = NULL, $t return 'cid:'. $content_id; } - + if ($file) { return $file; } - + $ret = $files; $files = array(); return $ret; @@ -166,7 +140,7 @@ function _mimemail_file($file = NULL, $t /** * - * @param $parts + * @param $parts * an array of parts to be included * each part is itself an array: * array( @@ -195,39 +169,39 @@ function _mimemail_file($file = NULL, $t * 'body' is the mime encoded multipart body of a mail. * 'headers' is an array that includes some headers for the mail to be sent. */ -function mimemail_multipart_body($parts, $content_type = 'multipart/mixed; charset=utf-8', $sub_part=false) { +function mimemail_multipart_body($parts, $content_type = 'multipart/mixed; charset=utf-8', $sub_part = FALSE) { $boundary = md5(uniqid(time())); $body = ''; $headers = array( 'Content-Type' => "$content_type; boundary=\"$boundary\"", ); if (!$sub_part) { - $headers['MIME-Version'] = '1.0'; + $headers['MIME-Version'] = '1.0'; $body = "This is a multi-part message in MIME format.\n"; } foreach ($parts as $part) { $part_headers = array(); - + if (isset($part['Content-ID'])) { $part_headers['Content-ID'] = '<'. $part['Content-ID'] .'>'; } - + if (isset($part['Content-Type'])) { $part_headers['Content-Type'] = $part['Content-Type']; } - + if (isset($part['Content-Disposition'])) { $part_headers['Content-Disposition'] = $part['Content-Disposition']; } - else { + else { $part_headers['Content-Disposition'] = 'inline'; } - + if ($part['Content-Transfer-Encoding']) { $part_headers['Content-Transfer-Encoding'] = $part['Content-Transfer-Encoding']; } - + // mail content provided as a string if (isset($part['content']) && $part['content']) { if (!isset($part['Content-Transfer-Encoding'])) { @@ -238,14 +212,14 @@ function mimemail_multipart_body($parts, $part_headers['Content-Type'] .= '; name="'. $part['name'] .'"'; $part_headers['Content-Disposition'] .= '; filename="'. $part['name'] .'"'; } - + // mail content references in a filename - } + } else { if (!isset($part['Content-Transfer-Encoding'])) { $part_headers['Content-Transfer-Encoding'] = 'base64'; } - + if (!isset($part['Content-Type'])) { $part['Content-Type'] = _mimemail_mimetype($part['file'], $type); } @@ -254,10 +228,10 @@ function mimemail_multipart_body($parts, $part_headers['Content-Type'] .= '; name="'. $part['name'] .'"'; $part_headers['Content-Disposition'] .= '; filename="'. $part['name'] .'"'; } - + $part_body = chunk_split(base64_encode(file_get_contents($part['file']))); } - + $body .= "\n--$boundary\n"; $body .= mimemail_rfc_headers($part_headers) ."\n\n"; $body .= $part_body; @@ -272,7 +246,7 @@ function mimemail_multipart_body($parts, * @param $body An HTML message body * @param $subject The message subject * @param $plaintext Whether the recipient prefers plaintext-only messages (default false) - * + * * @return * an array containing the elements 'header' and 'body'. * 'body' is the mime encoded multipart body of a mail. @@ -282,29 +256,39 @@ function mimemail_multipart_body($parts, * sub-parts for HTML and plaintext. Each subsequent part is the required * image/attachment */ -function mimemail_html_body($body, $subject, $plaintext=false, $text=null, $attachments = array()) { +function mimemail_html_body($body, $subject, $plaintext = FALSE, $text = NULL, $attachments = array()) { if (is_null($text)) { //generate plaintext alternative $text = mimemail_html_to_text($body); } if ($plaintext) { - return array( - 'body' => $text, - 'headers' => array('Content-Type' => 'text/plain; charset=utf-8'), - ); + //Plain mail without attachment + if (empty($attachments)) { + return array( + 'body' => $text, + 'headers' => array('Content-Type' => 'text/plain; charset=utf-8'), + ); + } + //Plain mail has attachement + else { + $parts = array(array( + 'content' => $text, + 'Content-Type' => 'text/plain; charset=utf-8', + )); + } } $content_type = 'multipart/alternative'; $text_part = array('Content-Type' => 'text/plain; charset=utf-8', 'content' => $text); - + //expand all local links $pattern = '/(]+href=")([^"]*)/emi'; $body = preg_replace($pattern, '"\\1"._mimemail_url("\2")', $body); - + $mime_parts = mimemail_extract_files($body); - $content = array($text_part, array_shift($mime_parts)); - $content = mimemail_multipart_body($content, $content_type, true); + $content = array($text_part, array_shift($mime_parts)); + $content = mimemail_multipart_body($content, $content_type, TRUE); $parts = array(array('Content-Type' => $content['headers']['Content-Type'], 'content' => $content['body'])); if ($mime_parts) { @@ -315,7 +299,7 @@ function mimemail_html_body($body, $subj foreach ($attachments as $a) { $a = (object) $a; $content_type = 'multipart/mixed'; - _mimemail_file($a->filepath, $a->filemime, 'attachment'); + _mimemail_file($a->filepath, $a->filename, $a->filemime, 'attachment'); $parts = array_merge($parts, _mimemail_file()); } @@ -375,7 +359,7 @@ function mimemail_parse($message) { // Make sure our text and html parts are accounted for if (isset($mail['html']) && !isset($mail['text'])) { - $mail['text'] = mimemail_html_to_text($mail['html']); + $mail['text'] = mimemail_html_to_text($mail['html']); } elseif (isset($mail['text']) && !isset($mail['html'])) { $mail['html'] = check_markup($mail['text']); @@ -505,27 +489,27 @@ function _mimemail_url($url) { if (strpos($url, '://')) { return $url; } - + if (preg_match('!mailto:!i', $url)) { return $url; } - + $url = preg_replace( '!'. base_path() .'!', '', $url, 1); $url = str_replace('?q=', '', $url); list($url, $fragment) = explode('#', $url, 2); list($path, $query) = explode('?', $url, 2); if (empty($path) && !empty($fragment)) { - return '#' . $fragment; + return '#'. $fragment; } - - return url($path, $query, $fragment, TRUE); + + return url($path, array('query' => $query, 'fragment' => $fragment, 'absolute' => TRUE)); } /** * Helper function to store processed urls. * - * @param $url Optional. + * @param $url Optional. * @param $refresh Optional. If TRUE refresh the cache. * * @return a count of stored if $url evaluates to false, the stored urls ortherwise. @@ -545,74 +529,26 @@ function _mimemail_urls($url = 0, $refre return $urls; } -function _mimemail_html2text() { - return array( - "/\r/" => '', - "/[\t]+/" => ' ', - '/]*>.*?<\/script>/i' => '', - '/]*>.*?<\/style>/i' => '', - '!]*>(.+?)
      !ie' => "\"\n\" .strtoupper('\\1').\"\n============================================================\n\"", - '!]*>(.+?)!ie' => "\"\n------------------------------------------------------------\n\" .'\\1'.\"\n------------------------------------------------------------\n\"", - '/]*>(.+?)<\/h3>/ie' => "\"\n\n\\1\n\n\"", - '/]*>(.+?)<\/h[456]>/ie' => "\"\n\\1\n\"", - '!]*>!i' => "\n\n\t", - '!
!i' => "\n\n", - '!]*>!i' => "\n\n", - '/]*>/i' => "\n", - '/(<(u|o|d)l[^>]*>|<\/(u|o|d)l>)/i' => "\n\n", - '!<(li|dt)[^>]*>!i' => " * ", - '!]*>!i' => " ", - '!!i' => "\n", - '/]*>/i' => "\n-------------------------\n", - '/(]*>|<\/table>)/i' => "\n\n", - '/(]*>|<\/tr>)/i' => "\n", - '/]*>(.+?)<\/td>/i' => "\t\t\\1\n", - '/]*>(.+?)<\/th>/i' => "\"\t\t\\1\n\"", - '/ /i' => " ", - '/"/i' => '"', - '/>/i' => '>', - '/</i' => '<', - '/&/i' => '&', - '/©/i' => '(c)', - '/™/i' => '(tm)', - '/“/' => '"', - '/”/' => '"', - '/–/' => '-', - '/’/' => "'", - '/&/' => '&', - '/©/' => '(c)', - '/™/' => '(tm)', - '/—/' => '--', - '/‘/' => '\'', - '/“/' => '"', - '/”/' => '"', - '/•/' => '*', - '/®/i' => '(R)', - '/•/i' => '*', - '/&[&;]+;/i' => '', - ); -} - /** - * Attempt to determine the mimetime from or filename . While not ideal, + * Attempt to determine the mimetime from or filename . While not ideal, * using the filename as a fallback ensures that images will appear inline * in HTML messages * * @param $name Name of the file - * + * * @return best-guess mimetype string */ -function _mimemail_mimetype($file, $type='') { +function _mimemail_mimetype($file, $type = '') { if ($type) { return $type; - } + } if (function_exists('mime_content_type')) { return mime_content_type($file); } // some common embedded/attachment types - $types = array( + $types = array( 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'gif' => 'image/gif', diff -upN sites/all/modules/mimemail-head/mimemail.info sites/all/modules/mimemail/mimemail.info --- sites/all/modules/mimemail-head/mimemail.info 2008-03-01 04:05:26.000000000 -0800 +++ sites/all/modules/mimemail/mimemail.info 2008-09-05 14:05:39.000000000 -0700 @@ -1,10 +1,5 @@ -; $Id: mimemail.info,v 1.1 2007/01/05 05:44:09 vauxia Exp $ +; $Id$ name = Mime Mail description = E-mail with HTML and attachments package = Mail - -; Information added by drupal.org packaging script on 2008-03-01 -version = "HEAD" -project = "mimemail" -datestamp = "1204373126" - +core = 6.x \ No newline at end of file diff -upN sites/all/modules/mimemail-head/mimemail.install sites/all/modules/mimemail/mimemail.install --- sites/all/modules/mimemail-head/mimemail.install 1969-12-31 16:00:00.000000000 -0800 +++ sites/all/modules/mimemail/mimemail.install 2008-09-05 14:01:57.000000000 -0700 @@ -0,0 +1,19 @@ + 'admin/settings/mimemail', - 'title' => t('Mail'), - 'description' => t('HTML E-mail settings'), - 'callback' => 'drupal_get_form', - 'callback arguments' => 'mimemail_settings', - 'access' => user_access('administer site configuration'), + $items['admin/settings/mimemail'] = array( + 'title' => 'Mime Mail', + 'description' => 'HTML E-mail settings', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('mimemail_settings'), + 'access arguments' => array('administer site configuration'), 'type' => MENU_NORMAL_ITEM, ); - $items[] = array( - 'path' => 'mimemail', - 'callback' => 'mimemail_post', - 'access' => variable_get('mimemail_incoming', FALSE), + $items['mimemail'] = array( + 'page callback' => 'mimemail_post', + 'access callback' => variable_get('mimemail_incoming', FALSE), 'type' => MENU_CALLBACK, ); return $items; } +/** + * Administration settings. + * + * @return + * The administration from. + */ function mimemail_settings() { // override the smtp_library value if mimemail is chosen to handle all mail @@ -43,14 +47,14 @@ function mimemail_settings() { } $engines = mimemail_get_engines(); - + $form = array(); $form['site_mail'] = array( - '#type' => 'textfield', - '#title' => t('E-mail address'), - '#default_value' => variable_get('site_mail', ini_get('sendmail_from')), - '#size' => 60, - '#maxlength' => 128, + '#type' => 'textfield', + '#title' => t('E-mail address'), + '#default_value' => variable_get('site_mail', ini_get('sendmail_from')), + '#size' => 60, + '#maxlength' => 128, '#description' => t('A valid e-mail address for this website, used by the auto-mailer during registration, new password requests, notifications, etc.') ); $form['mimemail']['mimemail_alter'] = array( @@ -59,6 +63,10 @@ function mimemail_settings() { '#default_value' => variable_get('mimemail_alter', 0), '#description' => t('Use the mime mail module to deliver all site messages. With this option, system emails will have styles and formatting'), ); + + $filter_format = variable_get('mimemail_format', FILTER_FORMAT_DEFAULT); + $form['mimemail']['mimemail_format'] = filter_form($filter_format, NULL, array("mimemail_format")); + $form['mimemail']['mimemail_textonly'] = array( '#type' => 'checkbox', '#title' => t('Plaintext email only'), @@ -85,24 +93,24 @@ function mimemail_settings() { '#required' => TRUE, '#description' => t('This string will be used to validate incoming messages. It can be anything, but must be used on both sides of the transfer'), ); - + // hide the settings if only 1 engine is available if (count($engines) == 1) { variable_set('mimemail_engine', key($engines)); $form['mimemail_engine'] = array( '#type' => 'hidden', - '#title' => t('E-mail engine'), - '#default_value' => variable_get('mimemail_engine', 'mail'), - '#options' => $engines, + '#title' => t('E-mail engine'), + '#default_value' => variable_get('mimemail_engine', 'mail'), + '#options' => $engines, '#description' => t('Choose an e-mail engine for sending mails from your site.') ); } else { $form['mimemail_engine'] = array( '#type' => 'select', - '#title' => t('E-mail engine'), - '#default_value' => variable_get('mimemail_engine', 'mail'), - '#options' => $engines, + '#title' => t('E-mail engine'), + '#default_value' => variable_get('mimemail_engine', 'mail'), + '#options' => $engines, '#description' => t('Choose an e-mail engine for sending mails from your site.') ); } @@ -111,7 +119,7 @@ function mimemail_settings() { $settings = module_invoke(variable_get('mimemail_engine', 'mail'), 'mailengine', 'settings'); if ($settings) { $form['mimemail_engine_settings'] = array( - '#type' => 'fieldset', + '#type' => 'fieldset', '#title' => t('Engine specific settings'), ); foreach ($settings as $name => $value) { @@ -127,16 +135,16 @@ function mimemail_settings() { } /** - * Implementation of hook_user() + * Implementation of hook_user(). */ -function mimemail_user($op, &$edit, &$user, $category='') { - if ( $op == 'form' && $category == 'account') { +function mimemail_user($op, &$edit, &$user, $category = '') { + if ($op == 'form' && $category == 'account') { $form = array(); $form['mimemail'] = array( '#type' => 'fieldset', '#title' => t('Email settings'), - '#weight' => 5, - '#collapsible' => true, + '#weight' => 5, + '#collapsible' => TRUE, ); $form['mimemail']['mimemail_textonly'] = array( '#type' => 'checkbox', @@ -145,23 +153,50 @@ function mimemail_user($op, &$edit, &$us '#description' => t('Check this option if you do not wish to receive email messages with graphics and styles'), ); return $form; - } + } return; } /** - * Send a mime-encoded email - * - * @param $sender The email address or user object - * @param $recipient An email address or user object * @param $subject An subject line string - * @param $body An HTML body - * @param $plaintext Whether to send message as plaintext only - * @param $headers Optional e-mail headers in a keyed array - * @param $text Optional plaintext portion of a multipart e-mail (instead of auto-generated) - * - * @return result from mail() call + * Sends a mime-encoded e-mail. + * + * This function first determines the mail engine to use, then prepares the + * message by calling the mail engine's prepare function, or + * mimemail_prepare() if another one does not exist, then sends the message. + * + * @param $sender + * The email address or user object who is sending the message. + * @param $recipient+ + * An email address or user object who is receiving the message. + * @param $subject + * A subject line string. + * @param $body + * The message body in HTML format. + * @param $plaintext + * Whether to send the message as plaintext only or HTML. If set to 1, Yes + * or TRUE, then the message will be sent as plaintext. + * @param $headers + * Optional e-mail headers in a keyed array. + * @param $text + * Optional plaintext portion of a multipart e-mail. + * @param $attachments + * An array of arrays which describe one or more attachments. The internal + * array consists of two parts: the file's path and the file's MIME type. + * The array of arrays looks something like this: + * Array + * ( + * [0] => Array + * ( + * [filepath] => '/path/to/file.name' + * [filemime] => 'mime/type' + * ) + * ) + * @param $mailkey + * An identifier for the message. + * @return + * An array containing the MIME encoded message, including headers and body. */ -function mimemail_prepare($sender, $recipient, $subject, $body, $plaintext=null, $headers=array(), $text=null, $attachments=array(), $mailkey = '') { +function mimemail_prepare($sender, $recipient, $subject, $body, $plaintext = NULL, $headers = array(), $text = NULL, $attachments = array(), $mailkey = '') { require_once dirname(__FILE__) .'/mimemail.inc'; @@ -171,7 +206,7 @@ function mimemail_prepare($sender, $reci 'mail' => variable_get('site_mail', ini_get('sendmail_from')), ); } - + // try to determine recpient's text mail preference if (is_null($plaintext)) { if (is_object($recipient)) { @@ -187,7 +222,7 @@ function mimemail_prepare($sender, $reci } } $subject = mime_header_encode($subject); - + $plaintext = $plaintext || variable_get('mimemail_textonly', 0); $sender = mimemail_address($sender); $mail = mimemail_html_body(theme('mimemail_message', $body, $mailkey), $subject, $plaintext, $text, $attachments); @@ -203,12 +238,11 @@ function mimemail_prepare($sender, $reci return $message; } -function mimemail($sender, $recipient, $subject, $body, $plaintext = NULL, $headers=array(), $text = NULL, $attachments = array(), $mailkey = '') { - +function mimemail($sender, $recipient, $subject, $body, $plaintext = NULL, $headers = array(), $text = NULL, $attachments = array(), $mailkey = '') { $engine = variable_get('mimemail_engine', 'mimemail') .'_mailengine'; - + if (!function_exists($engine)) { - return false; + return FALSE; } $engine_prepare = variable_get('mimemail_engine', 'mimemail') .'_prepare'; @@ -221,13 +255,14 @@ function mimemail($sender, $recipient, $ return $engine('send', $message); - return false; + return FALSE; } /** - * Returns available mailer engines. + * Retreives a list of all available mailer engines. * - * @return an array of mailer engine names. + * @return + * An array of mailer engine names. */ function mimemail_get_engines() { $engines = array(); @@ -241,35 +276,42 @@ function mimemail_get_engines() { } /** - * Default mailengine + * The default mailengine. + * + * @param $op + * The operation to perform on the message. + * @param $message + * The message to be sent. + * @return + * Returns TRUE if the operation was successful or FALSE if it was not. */ function mimemail_mailengine($op, $message = array()) { //default values $message = array_merge( array( - 'address' => '', - 'subject' => '', - 'body' => '', - 'sender' => '', - 'headers' => '', + 'address' => '', + 'subject' => '', + 'body' => '', + 'sender' => '', + 'headers' => '', ), $message); - + switch ($op) { case 'name': return t('Mime Mail'); - + case 'description': return t("Default mailing engine using drupal_mail()."); - + case 'settings': //not implemented - return false; - + return FALSE; + case 'multiple': case 'single': case 'send': if (!is_array($message['address'])) { $message['address'] = array($message['address']); } - $status = true; + $status = TRUE; foreach ($message['address'] as $a) { $status = mail( $a, @@ -277,32 +319,60 @@ function mimemail_mailengine($op, $messa $message['body'], mimemail_rfc_headers($message['headers']) ) && $status; - + } return $status; } - return false; + return FALSE; } +/** + * Overrides Drupal's default mail sending process. + * + * @param $mailkey + * An identifier for the message. + * @param $to + * An email address or user object who is receiving the message. + * @param $subject + * A subject line string. + * @param $body + * The message body in HTML format. + * @param $from + * The email address or user object who is sending the message. + * @param $headers + * Optional e-mail headers in a keyed array. + * @return + * Returns the resultss of the call to mimemail(). + */ if (strpos(variable_get('smtp_library', ''), 'mimemail') && !function_exists('drupal_mail_wrapper')) { function drupal_mail_wrapper($mailkey, $to, $subject, $body, $from, $headers) { + $from = $message['from']; + $to = $message['to']; + $subject = $message['subject']; + if ($format = variable_get('mimemail_format', FILTER_FORMAT_DEFAULT)) { + $body = check_markup($body, $format); + } + else { + $body = $message['body']; + } + $headers = isset($message['headers']) ? $message['headers'] : array(); + $mailkey = isset($message['mailkey']) ? $message['mailkey'] : ''; return mimemail($from, $to, $subject, $body, NULL, $headers, NULL, array(), $mailkey); } -} - -function mimemail_mail_alter($mailkey, &$recipient, &$subject, &$body, &$sender, &$headers) { - - if (!variable_get('mimemail_alter', 0)) return; - - // attempt to fixup non-html messages that are being sent through drupal_mail - // I'm open to suggestions for better ways of doing this - $body = check_markup($body, FILTER_FORMAT_DEFAULT); - return; } +/** + * Receive messages POSTed from an external source. + * + * This function enables messages to be sent via POST or some other RFC822 + * source input (e.g. directly from a mail server). + * + * @return + * The POSTed message. + */ function mimemail_post() { $message = $_POST['message']; $token = $_POST['token']; @@ -315,39 +385,47 @@ function mimemail_post() { return mimemail_incoming($message); } +/** + * Parses an externally received message. + * + * @param $message + * The message to parse. + */ function mimemail_incoming($message) { require_once dirname(__FILE__) .'/mimemail.inc'; $mail = mimemail_parse($message); - foreach (module_implements('mimemail_incoming_alter') as $module) { - call_user_func_array($module .'_mimemail_incoming_alter', $mail); + foreach (module_implements('mimemail_incoming_alter') as $module) { + call_user_func_array($module .'_mimemail_incoming_alter', $mail); } module_invoke_all('mimemail_incoming', $mail); } /** - * Formats an address string - * TODO could use some enhancement and stress testing - * - * @param $address - a user object, a text email address or an array containing name, mail - * @return formatted address string + * Formats an address string. + * TODO could use some enhancement and stress testing. + * + * @param $address + * A user object, a text email address or an array containing name, mail. + * @return + * A formatted address string or FALSE. */ function mimemail_address($address) { - + if (is_array($address)) { - + // it's an array containing 'mail' and/or 'name' if (isset($address['mail'])) { $output = ''; if (empty($address['name'])) { return $address['mail']; - } + } else { - return '"'. addslashes($address['name']) .'" <'. $address['mail'] .'>'; + return '"'. addslashes(mime_header_encode($address['name'])) .'" <'. $address['mail'] .'>'; } } - + // it's an array of address items $addresses = array(); foreach ($address as $a) { @@ -355,12 +433,12 @@ function mimemail_address($address) { } return $addresses; } - + // it's a user object if (is_object($address) && isset($address->mail)) { - return '"'. addslashes($address->name) .'" <'. $address->mail .'>'; + return '"'. addslashes(mime_header_encode($address->name)) .'" <'. $address->mail .'>'; } - + // it's formatted or unformatted string // TODO shouldn't assume it's valid - should try to re-parse if (is_string($address)) { @@ -370,18 +448,36 @@ function mimemail_address($address) { // it's null. return the site default address if (is_null($address)) { return array( - 'name' => variable_get('site_name', 'Drupal'), + 'name' => mime_header_encode(variable_get('site_name', 'Drupal')), 'mail' => variable_get('site_mail', ini_get('sendmail_from')), ); } - return false; + return FALSE; } /** - * Themeable message body + * Implementation of hook_theme(). + */ +function mimemail_theme() { + return array( + 'mimemail_message' => array( + 'arguments' => array('body' => NULL, 'mailkey' => NULL) + ) + ); +} + +/** + * Themes the message body. + * + * @param $body + * The message body to theme. + * @param $mailkey + * An identifier for the message. + * @return + * The themed HTML message body. */ -function theme_mimemail_message($body, $mailkey = null) { +function theme_mimemail_message($body, $mailkey = NULL) { $output = ''; $output .= ''; @@ -392,7 +488,7 @@ function theme_mimemail_message($body, $ $output .= '