00001 <?php
00002 # This file is part of the Savane project
00003 # <http://gna.org/projects/savane/>
00004 #
00005 # $Id: sendmail.php 5442 2006-02-19 15:14:12Z yeupou $
00006 #
00007 # Copyright 2003-2005 (c) Mathieu Roy <yeupou--gnu.org>
00008 #
00009 # The Savane project is free software; you can redistribute it and/or
00010 # modify it under the terms of the GNU General Public License
00011 # as published by the Free Software Foundation; either version 2
00012 # of the License, or (at your option) any later version.
00013 #
00014 # The Savane project is distributed in the hope that it will be useful,
00015 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00017 # GNU General Public License for more details.
00018 #
00019 # You should have received a copy of the GNU General Public License
00020 # along with the Savane project; if not, write to the Free Software
00021 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00022
00023 # Every mails sent should be using functions listed here.
00024
00025 # The function that finally send the mail.
00026 # Every mail sent by Savannah should be using that function which
00027 # works like mail().
00028 # Note: $to can be a coma-separated list.
00029 # $from and $to can contain user names
00030 function sendmail_mail ($from,
00031 $to,
00032 $subject,
00033 $message, #4
00034 $savannah_project=0,
00035 $savannah_artifact=0,
00036 $savannah_artifact_id=0,
00037 $reply_to=0, # 8
00038 $additional_headers=0,
00039 $exclude_list=0)
00040 {
00041
00042
00043 # Make sure that users cannot insert malicious content
00044 # (apart in message, which is not part of the headers)
00045 $to = stripslashes($to);
00046 $from = stripslashes($from);
00047 $subject = stripslashes($subject);
00048
00049 # Make sure the message respect the 78chars max width
00050 # Make also sure we havent got excessive slashes escaping
00051 $message = wordwrap($message, 78);
00052
00053 # Convert ; into
00054 $to = ereg_replace(";", ",", $to);
00055 # Transform $to in an ordered list, without duplicates
00056 # (remove blankspaces)
00057 $to = array_unique(explode(",", ereg_replace(" ", "", $to)));
00058
00059 # If $from is a login name, write nice From: field
00060 $fromuid = user_getid($from);
00061 if (user_exists($fromuid))
00062 {
00063 $from = user_getrealname($fromuid, 1)." <".user_getemail($fromuid).">";
00064 }
00065
00066 # Write the add. headers
00067 # Note: RFC-821 recommends to use \r\n as line break in headers but \n
00068 # works and there are report of failures with \r\n so we let \n for now.
00069 $more_headers = "From: ".sendmail_encode_header_content($from)."\n";
00070 if ($reply_to)
00071 { $more_headers .= "Reply-To: ".$reply_to."\n"; }
00072 $more_headers .= "X-Savane-Server: ".$_SERVER['SERVER_NAME'].":".$_SERVER['SERVER_PORT']." [".$_SERVER['SERVER_ADDR']."]\n";
00073
00074 # Necessary for proper utf-8 support
00075 $more_headers .= "MIME-Version: 1.0\n";
00076 $more_headers .= "Content-Type: text/plain;charset=UTF-8\n";
00077
00078 # Savane details
00079 if ($savannah_project)
00080 { $more_headers .= "X-Savane-Project: ".$savannah_project."\n"; }
00081 if ($savannah_artifact)
00082 { $more_headers .= "X-Savane-Tracker: ".$savannah_artifact."\n"; }
00083 if ($savannah_artifact_id)
00084 { $more_headers .= "X-Savane-Item-ID: ".$savannah_artifact_id."\n"; }
00085 if ($additional_headers)
00086 { $more_headers .= $additional_headers."\n"; }
00087
00088 # User details.
00089 # Tell what is the user agent, tell which authenticated user made
00090 # the mail to be sent
00091 $more_headers .= "User-Agent: ".$_SERVER['HTTP_USER_AGENT']."\n";
00092 if (user_isloggedin())
00093 {
00094 $more_headers .= "X-Apparently-From: ".$_SERVER['REMOTE_ADDR']." (Savane authenticated user ".user_getname(user_getid()).")\n";
00095 }
00096 else
00097 {
00098 $more_headers .= "X-Apparently-From: ".$_SERVER['REMOTE_ADDR']."\n";
00099 }
00100
00101 # Message ID
00102 $msg_id = sendmail_create_msgid();
00103 $more_headers .= "Message-Id: <".$msg_id.">\n";
00104 # Add refs
00105 if ($savannah_artifact && $savannah_artifact_id)
00106 {
00107 $more_headers .= "References: ".trackers_get_msgid($savannah_artifact, $savannah_artifact_id)."\n";
00108 $more_headers .= "In-Reply-To: ".trackers_get_msgid($savannah_artifact, $savannah_artifact_id, true)."\n";
00109 }
00110
00111 # Add a signature for the server
00112 $message .= "\n\n_______________________________________________
00113 ".sprintf(_("Message sent via/by %s"), $GLOBALS['sys_name'])."
00114 http://".$GLOBALS['sys_default_domain'].$GLOBALS['sys_home']."\n";
00115
00116 # Register the message id for future references
00117 if ($savannah_artifact && $savannah_artifact_id)
00118 {
00119 trackers_register_msgid($msg_id, $savannah_artifact, $savannah_artifact_id);
00120 }
00121
00122 # If there's an exclude list, create an array
00123 # Convert ; into
00124 $exclude = array();
00125 if ($exclude_list)
00126 {
00127 $exclude_list = ereg_replace(";", ",", $exclude_list);
00128 $exclude = array_unique(explode(",", ereg_replace(" ", "", $exclude_list)));
00129 }
00130
00131 while (list(,$v) = each($exclude))
00132 {
00133 if ($v)
00134 { $exclude[$v] = 1; }
00135 }
00136
00137
00138 # Forge the real to list, by parsing every item of the $to list
00139 unset($real_to);
00140 $list = array();
00141 $user_subject = array();
00142 $user_name = array();
00143
00144 while (list($k,$v) = each($to))
00145
00146 {
00147 if (is_numeric($v)) {
00148 $touid = $v;
00149 } else {
00150 $touid = user_getid($v);
00151 }
00152 # Exists in the exclude array? Skip it
00153 if ($exclude[$v])
00154 { continue; }
00155
00156 $i++;
00157 unset($skip);
00158 # If an address is a username, get the email address from
00159 # the database.
00160 # If nothing is found, just let the username - there's maybe a
00161 # local alias.
00162 if (!ereg("@", $v))
00163 {
00164 if (user_exists($touid))
00165 {
00166 # Exists in the exclude array? Skip it
00167 if (is_array($exclude) && array_key_exists(user_getname($touid), $exclude))
00168 { continue; }
00169 # Does the user have a specific subject line?
00170 if (user_get_preference("subject_line", $touid) != "")
00171 {
00172 $list[$i] = $v;
00173 $user_subject[$v] = sendmail_format_subject_line(user_get_preference("subject_line", $touid), $savannah_project, $savannah_artifact, $savannah_artifact_id)." ".$subject;
00174 $user_name[$v] = user_getrealname($touid, 1)." <".user_getemail($touid).">";
00175 $skip = 1;
00176 }
00177
00178 $v = user_getrealname($touid, 1)." <".user_getemail($touid).">";
00179
00180 }
00181 }
00182 # If $v is set, add it to the list,
00183 # unless user want a specific subject line
00184 if (!$skip)
00185 {
00186 $real_to .= $v.", ";
00187 }
00188
00189 }
00190
00191 # Add eventually info on the subject
00192 if ($savannah_artifact && $savannah_artifact_id)
00193 {
00194 $subject = "[".utils_get_tracker_prefix($savannah_artifact)." #".$savannah_artifact_id."] ".$subject;
00195 }
00196
00197 # Remove the extra ", " at the end of the list
00198 $real_to = substr($real_to,0,-2);
00199
00200 # Beuc - 20050316
00201 # That's what I intended to do:
00202
00203 # All newlines should be \r\n; this is apparently more
00204 # RFC821-compliant.
00205 # $message = preg_replace("/(?<!\r)\n/", "\r\n", $message);
00206
00207 # However the opposite is certainly more Mailman-compliant; a bug
00208 # report has been posted to the Mailman team - wait&see [bug #1980]
00209 $message = str_replace("\r\n", "\n", $message);
00210
00211 # Send the mail in UTF-8.
00212 # Normally, nothing non-ASCII should be contained in To: field, apart the
00213 # real names.
00214 if ($real_to)
00215 {
00216 $ret .= mail(sendmail_encode_header_content($real_to), sendmail_encode_header_content($subject), $message, $more_headers);
00217 fb(sprintf(_("Mail sent to %s"), utils_email($real_to, 1)));
00218 }
00219
00220 # Send mails with specific subject line
00221 while (list(,$v) = each($list))
00222 {
00223 $ret .= mail(sendmail_encode_header_content($user_name[$v]), sendmail_encode_header_content($user_subject[$v]), $message, $more_headers);
00224 fb(sprintf(_("Mail sent to %s"), utils_email($user_name[$v], 1)));
00225 }
00226
00227 return $ret;
00228 }
00229
00230
00231 # Needed to send utf-8 headers:
00232 # Take a look at http://www.faqs.org/rfcs/rfc2047.html
00233 # We should use mb_encode_mimeheader() but it just does not work.
00234 #
00235 # We must not encode starting and ending quotes.
00236 # We assume there could be only 2 quotes. Otherwise it would be a malformed
00237 # address.
00238 # The easy way we use to do this is to simply consider as one string the
00239 # content of the quote, if any. If so, we are not working word per word but
00240 # it saves us the time of searching for quotes in every words.
00241 function sendmail_encode_header_content ($header, $charset="UTF-8")
00242 {
00243 if (ereg('"', $header))
00244 {
00245 # quotes found, we each quoted part will be a string to encode
00246 $words = split('"', $header);
00247 $withquotes = 1;
00248 }
00249 else
00250 {
00251 # otherwise, the default behavior is to consider words as strings to
00252 # encode
00253 $words = split(' ', $header);
00254 }
00255
00256 while (list($key,$word) = each($words))
00257 {
00258 # Check word per word if they need encoding
00259 if (!utils_is_ascii($word)) {
00260 $words[$key] = "=?$charset?B?".base64_encode($word)."?=";
00261 }
00262 }
00263
00264 if ($withquotes)
00265 {
00266 return join('"', $words);
00267 }
00268 else
00269 {
00270 return join(' ', $words);
00271 }
00272 }
00273
00274
00275 # A form for logged in users to send mails to others users
00276 function sendmail_form_message ($form_action, $user_id)
00277 {
00278 global $HTML;
00279 print $HTML->box_top(sprintf(_("Send a Message to %s"),user_getrealname($user_id)));
00280 print '<p class="warn">'.("If you are writing for help, did you read the project
00281 documentation first? Try to provide any potentially useful information you can think of.").'</p>';
00282
00283 # We do not really bother finding out the realname + email, sendmail_mail()
00284 # will do it.
00285 print '
00286 <form action="'.$form_action.'" method="post">
00287 <input type="hidden" name="touser" value="'.$user_id.'" />
00288 <input type="hidden" name="fromuser" value="'.user_getname().'" />
00289
00290 <span class="preinput">'._("From:").'</span><br /> '.user_getrealname(user_getid(), 1).' <'.user_getemail(user_getid()).'><br />
00291 <span class="preinput">'._("Mailer:").'</span><br /> '.utils_cutstring($GLOBALS['HTTP_USER_AGENT'], "50").'<br />
00292 <span class="preinput">'._("Subject:").'</span><br /> <input type="text" name="subject" size="60" maxlength="45" value="" /><br />
00293 <span class="preinput">'._("Message:").'</span><br />
00294 <textarea name="body" rows="20" cols="60"></textarea>
00295
00296 <p align="center"><input type="submit" name="send_mail" value="Send Message" /></p>
00297 </form>';
00298 print $HTML->box_bottom();
00299 }
00300
00301 function sendmail_format_subject_line ($subject_line, $savannah_project="", $savannah_artifact="", $savannah_artifact_id="")
00302 {
00303
00304 $subject_line = ereg_replace("%SERVER", $GLOBALS['sys_default_domain'], $subject_line);
00305 $subject_line = ereg_replace("%PROJECT", $savannah_project, $subject_line);
00306 $subject_line = ereg_replace("%TRACKER", $savannah_artifact, $subject_line);
00307 return ereg_replace("%ITEM", "#".$savannah_artifact_id, $subject_line);
00308 }
00309
00310 function sendmail_create_msgid ()
00311 {
00312 mt_srand((double)microtime()*1000000);
00313 return date("Ymd-His", time()).".sv".user_getid().".".mt_rand(0,100000)."@".$_SERVER["HTTP_HOST"];
00314 }
00315
00316 ?>