khanat-opennel-code/code/ryzom/tools/server/ryzom_ams/ams_lib/autoload/mail_handler.php

406 lines
18 KiB
PHP
Raw Normal View History

<?php
2013-08-10 11:59:36 +00:00
class Mail_Handler{
private $db;
public function mail_fork() {
//Start a new child process and return the process id!
2013-08-10 11:59:36 +00:00
$pid = pcntl_fork();
return $pid;
}
2013-08-10 11:59:36 +00:00
2013-08-20 00:08:12 +00:00
public static function send_ticketing_mail($ticketObj, $content, $type, $sendingId = 0) {
2013-08-13 15:16:43 +00:00
global $TICKET_MAILING_SUPPORT;
if($TICKET_MAILING_SUPPORT){
//$txt = "";
//$subject = "";
2013-08-20 00:08:12 +00:00
if($sendingId == 0){
//if it is not forwarded (==public == which returns 0) then make it NULL which is needed to be placed in the DB.
2013-08-20 00:08:12 +00:00
$sendingId = NULL;
}
$author = $ticketObj->getAuthor();
$webUser = new WebUsers($author);
2013-08-13 15:16:43 +00:00
//if the author of the ticket wants to receive mail, then send it!
if($webUser->getReceiveMail()){
switch($type){
case "REPLY":
$txt = "---------- Ticket #". $ticketObj->getTId() . " ----------\n You received a new reply on your ticket: " . $ticketObj->getTitle() .
"\n --------------------\n\n";
$subject = "New reply on [Ticket #" . $ticketObj->getTId() ."]";
$endTxt = "\n\n----------\nYou can reply on this message to answer directly on the ticket!";
$txt = $txt . $content . $endTxt;
2013-08-20 00:08:12 +00:00
self::send_mail($author,$subject,$txt, $ticketObj->getTId(),$sendingId);
break;
case "NEW":
$txt = "---------- Ticket #". $ticketObj->getTId() . " ----------\n Your ticket: " . $ticketObj->getTitle() . " is newly created";
$txt = $txt . "\n --------------------\n\n";
$subject = "New ticket created [Ticket #" . $ticketObj->getTId() ."]";
$endTxt = "\n\n----------\nYou can reply on this message to answer directly on the ticket!";
$txt = $txt . $content . $endTxt;
2013-08-20 00:08:12 +00:00
self::send_mail($author,$subject,$txt, $ticketObj->getTId(), $sendingId);
break;
}
}
2013-08-13 15:16:43 +00:00
}
}
2013-08-10 11:59:36 +00:00
2013-08-17 01:06:22 +00:00
public static function send_mail($recipient, $subject, $body, $ticket_id = 0, $from = NULL) {
2013-08-20 00:08:12 +00:00
$id_user = NULL;
2013-08-10 11:59:36 +00:00
if(is_numeric($recipient)) {
$id_user = $recipient;
$recipient = NULL;
}
2013-08-20 00:08:12 +00:00
2013-08-13 15:16:43 +00:00
$query = "INSERT INTO email (Recipient,Subject,Body,Status,Attempts,Sender,UserId,MessageId,TicketId) VALUES (:recipient, :subject, :body, :status, :attempts, :sender, :id_user, :messageId, :ticketId)";
$values = array('recipient' => $recipient, 'subject' => $subject, 'body' => $body, 'status' => 'NEW', 'attempts'=> 0, 'sender' => $from,'id_user' => $id_user, 'messageId' => 0, 'ticketId'=> $ticket_id);
$db = new DBLayer("lib");
$db->execute($query, $values);
2013-08-10 11:59:36 +00:00
}
//the main function
function cron() {
2013-08-10 11:59:36 +00:00
global $cfg;
global $MAIL_LOG_PATH;
$default_groupemail = $cfg['mail']['default_groupemail'];
$default_groupname = $cfg['mail']['default_groupname'];
2013-08-16 20:24:11 +00:00
/*
2013-08-10 11:59:36 +00:00
$inbox_host = $cfg['mail']['host'];
$oms_reply_to = "Ryzom Ticketing Support <ticketing@".$inbox_host.">";*/
global $MAIL_DIR;
error_log("========================================================\n", 3, $MAIL_LOG_PATH);
error_log("mailing cron Job started at: ". Helpers::outputTime(time(),0) . "\n", 3, $MAIL_LOG_PATH);
2013-08-10 11:59:36 +00:00
//creates child process
$pid = self::mail_fork();
$pidfile = '/tmp/ams_cron_email_pid';
2013-08-10 11:59:36 +00:00
if($pid) {
2013-08-11 23:11:48 +00:00
// We're the parent process, do nothing!
//INFO: if $pid =
//-1: "Could not fork!\n";
// 0: "In child!\n";
//>0: "In parent!\n";
2013-08-11 23:11:48 +00:00
2013-08-10 11:59:36 +00:00
} else {
2013-08-20 00:08:12 +00:00
//deliver new mail
//make db connection here because the children have to make the connection.
$this->db = new DBLayer("lib");
//if $pidfile doesn't exist yet, then start sending the mails that are in the db.
2013-08-10 11:59:36 +00:00
if(!file_exists($pidfile)) {
//create the file and write the child processes id in it!
2013-08-10 11:59:36 +00:00
$pid = getmypid();
$file = fopen($pidfile, 'w');
fwrite($file, $pid);
fclose($file);
//select all new & failed emails & try to send them
//$emails = db_query("select * from email where status = 'NEW' or status = 'FAILED'");
$statement = $this->db->executeWithoutParams("select * from email where Status = 'NEW' or Status = 'FAILED'");
$emails = $statement->fetchAll();
2013-08-10 11:59:36 +00:00
foreach($emails as $email) {
2013-08-12 21:56:58 +00:00
$message_id = self::new_message_id($email['TicketId']);
//if recipient isn't given, then use the email of the id_user instead!
if(!$email['Recipient']) {
2013-08-13 15:16:43 +00:00
$email['Recipient'] = Ticket_User::get_email_by_user_id($email['UserId']);
2013-08-10 11:59:36 +00:00
}
//create sending email adres based on the $sender id which refers to the department id
if($email['Sender'] == NULL) {
$from = $default_groupname ." <".$default_groupemail.">";
2013-08-10 11:59:36 +00:00
} else {
$group = Support_Group::getGroup($email['Sender']);
$from = $group->getName()." <".$group->getGroupEmail().">";
2013-08-10 11:59:36 +00:00
}
2013-08-12 21:56:58 +00:00
$headers = "From: $from\r\n" . "Message-ID: " . $message_id ;
if(mail($email['Recipient'], $email['Subject'], $email['Body'], $headers)) {
2013-08-10 11:59:36 +00:00
$status = "DELIVERED";
error_log("Emailed {$email['Recipient']}\n", 3, $MAIL_LOG_PATH);
2013-08-10 11:59:36 +00:00
} else {
$status = "FAILED";
error_log("Email to {$email['Recipient']} failed\n", 3, $MAIL_LOG_PATH);
2013-08-10 11:59:36 +00:00
}
//change the status of the emails.
$this->db->execute('update email set Status = ?, MessageId = ?, Attempts = Attempts + 1 where MailId = ?', array($status, $message_id, $email['MailId']));
}
2013-08-10 11:59:36 +00:00
unlink($pidfile);
}
2013-08-10 11:59:36 +00:00
// Check mail
2013-08-16 20:24:11 +00:00
$sGroups = Support_Group::getGroups();
//decrypt passwords in the db!
$crypter = new MyCrypt($cfg['crypt']);
foreach($sGroups as $group){
2013-08-20 00:08:12 +00:00
$group->setIMAP_Password($crypter->decrypt($group->getIMAP_Password()));
}
2013-08-16 20:24:11 +00:00
$defaultGroup = new Support_Group();
2013-08-17 01:06:22 +00:00
$defaultGroup->setSGroupId(0);
2013-08-16 20:24:11 +00:00
$defaultGroup->setGroupEmail($default_groupemail);
$defaultGroup->setIMAP_MailServer($cfg['mail']['default_mailserver']);
$defaultGroup->setIMAP_Username($cfg['mail']['default_username']);
$defaultGroup->setIMAP_Password($cfg['mail']['default_password']);
//add default group to the list
2013-08-16 20:24:11 +00:00
$sGroups[] = $defaultGroup;
2013-08-11 23:11:48 +00:00
2013-08-16 20:24:11 +00:00
foreach($sGroups as $group){
//check if group has mailing stuff filled in!
2013-08-20 00:08:12 +00:00
if($group->getGroupEmail() != "" && $group->getIMAP_MailServer() != "" && $group->getIMAP_Username() != "" && $group->getIMAP_Password() != ""){
$mbox = imap_open($group->getIMAP_MailServer(), $group->getIMAP_Username(), $group->getIMAP_Password()) or die('Cannot connect to mail server: ' . imap_last_error());
$message_count = imap_num_msg($mbox);
for ($i = 1; $i <= $message_count; ++$i) {
//return task ID
2013-08-20 00:08:12 +00:00
$tkey = self::incoming_mail_handler($mbox, $i,$group);
2013-08-20 00:08:12 +00:00
if($tkey) {
//TODO: base file on Ticket + timestamp
2013-08-20 00:08:12 +00:00
$file = fopen($MAIL_DIR."/ticket".$tkey, 'w');
error_log("Email was written to ".$MAIL_DIR."/ticket".$tkey."\n", 3, $MAIL_LOG_PATH);
fwrite($file, imap_fetchheader($mbox, $i) . imap_body($mbox, $i));
fclose($file);
//mark message $i of $mbox for deletion!
imap_delete($mbox, $i);
}
2013-08-16 20:24:11 +00:00
}
//delete marked messages
imap_expunge($mbox);
imap_close($mbox);
2013-08-11 23:11:48 +00:00
}
2013-08-10 11:59:36 +00:00
}
error_log("Child Cron job finished at ". Helpers::outputTime(time(),0) . "\n", 3, $MAIL_LOG_PATH);
error_log("========================================================\n", 3, $MAIL_LOG_PATH);
}
2013-08-20 00:08:12 +00:00
2013-08-10 11:59:36 +00:00
}
2013-08-12 21:56:58 +00:00
function new_message_id($ticketId) {
2013-08-10 11:59:36 +00:00
$time = time();
$pid = getmypid();
global $cfg;
global $ams_mail_count;
$ams_mail_count = ($ams_mail_count == '') ? 1 : $ams_mail_count + 1;
2013-08-12 21:56:58 +00:00
return "<ams.message".".".$ticketId.".".$pid.$ams_mail_count.".".$time."@".$cfg['mail']['host'].">";
2013-08-10 11:59:36 +00:00
}
2013-08-12 21:56:58 +00:00
function get_ticket_id_from_subject($subject){
$startpos = strpos($subject, "[Ticket #");
2013-08-17 01:06:22 +00:00
if($startpos){
$tempString = substr($subject, $startpos+9);
$endpos = strpos($tempString, "]");
if($endpos){
$ticket_id = substr($tempString, 0, $endpos);
}else{
$ticket_id = 0;
}
}else{
$ticket_id = 0;
}
2013-08-12 21:56:58 +00:00
return $ticket_id;
}
2013-08-10 11:59:36 +00:00
2013-08-12 21:56:58 +00:00
2013-08-17 01:06:22 +00:00
function incoming_mail_handler($mbox,$i,$group){
2013-08-12 21:56:58 +00:00
global $MAIL_LOG_PATH;
2013-08-12 21:56:58 +00:00
$header = imap_header($mbox, $i);
$subject = self::decode_utf8($header->subject);
2013-08-17 01:06:22 +00:00
$entire_email = imap_fetchheader($mbox, $i) . imap_body($mbox, $i);
$subject = self::decode_utf8($header->subject);
$to = $header->to[0]->mailbox;
2013-08-20 00:08:12 +00:00
$from = $header->from[0]->mailbox . '@' . $header->from[0]->host;
$fromEmail = $header->from[0]->mailbox . '@' . $header->from[0]->host;
2013-08-17 01:06:22 +00:00
$txt = self::get_part($mbox, $i, "TEXT/PLAIN");
//$html = self::get_part($mbox, $i, "TEXT/HTML");
2013-08-12 21:56:58 +00:00
2013-08-17 01:06:22 +00:00
//get the id out of the email address of the person sending the email.
if($from !== NULL && !is_numeric($from)){
$from = Ticket_User::get_id_from_email($from);
}
2013-08-12 21:56:58 +00:00
//get ticket_id out of the message-id or else out of the subject line
$ticket_id = 0;
if(isset($header->references)){
$pieces = explode(".", $header->references);
if($pieces[0] == "<ams"){
$ticket_id = $pieces[2];
}else{
$ticket_id = self::get_ticket_id_from_subject($subject);
}
}else{
$ticket_id = self::get_ticket_id_from_subject($subject);
}
2013-08-17 01:06:22 +00:00
//if ticket id is found, that means it is a reply on an existing ticket
2013-08-12 21:56:58 +00:00
if($ticket_id){
2013-08-20 00:08:12 +00:00
$ticket = new Ticket();
$ticket->load_With_TId($ticket_id);
2013-08-13 15:16:43 +00:00
2013-08-17 01:06:22 +00:00
//if email is sent from an existing email address in the db (else it will give an error while loading the user object)
if($from != "FALSE"){
2013-08-17 01:06:22 +00:00
$user = new Ticket_User();
$user->load_With_TUserId($from);
2013-08-20 00:08:12 +00:00
2013-08-17 01:06:22 +00:00
//if user has access to it!
if((Ticket_User::isMod($user) or ($ticket->getAuthor() == $user->getTUserId())) and $txt != ""){
2013-08-20 00:08:12 +00:00
Ticket::createReply($txt, $user->getTUserId(), $ticket->getTId(), 0);
error_log("Email found that is a reply to a ticket at:".$group->getGroupEmail()."\n", 3, $MAIL_LOG_PATH);
2013-08-20 00:08:12 +00:00
}else{
//if user has no access to it
//Warn real ticket owner + person that send the mail
$subject_warnAuthor = "Someone tried to reply to your ticket: [Ticket #" . $ticket->getTId() ."]";
$body_warnAuthor = "Someone tried to reply at your ticket: " . $ticket->getTitle() ."by sending an email from ".$fromEmail."! Please use the email address matching to your account if you want to auto reply!\n\n
If ". $fromEmail. " isn't one of your email addresses, please contact us by replying to this ticket!" ;
Mail_Handler::send_mail($ticket->getAuthor(), $subject_warnAuthor , $body_warnAuthor, $ticket->getTId(), NULL);
$subject_warnSender = "You tried to reply to someone elses ticket!";
$body_warnSender = "It seems you tried to reply to someone elses ticket, please use the matching email address to that account!\n\n
This action is notified to the real ticket owner!" ;
Mail_Handler::send_mail($from, $subject_warnSender , $body_warnSender, $ticket->getTId(), NULL);
error_log("Email found that was a reply to a ticket, though send by another user to ".$group->getGroupEmail()."\n", 3, $MAIL_LOG_PATH);
2013-08-17 01:06:22 +00:00
}
2013-08-20 00:08:12 +00:00
}else{
2013-08-20 00:08:12 +00:00
//if a reply to a ticket is being sent by a non-user!
//Warn real ticket owner + person that send the mail
$subject_warnAuthor = "Someone tried to reply to your ticket: [Ticket #" . $ticket->getTId() ."]";
$body_warnAuthor = "Someone tried to reply at your ticket:' " . $ticket->getTitle() ."' by sending an email from ".$fromEmail." ! Please use the email address matching to your account if you want to auto reply!\n\n
If ". $fromEmail. " isn't one of your email addresses, please contact us by replying to this ticket!" ;
Mail_Handler::send_mail($ticket->getAuthor(), $subject_warnAuthor , $body_warnAuthor, $ticket->getTId(), NULL);
$subject_warnSender = "You tried to reply to someone's ticket!";
$body_warnSender = "It seems you tried to reply to someone's ticket, However this email address isn't linked to any account, please use the matching email address to that account!\n\n
This action is notified to the real ticket owner!" ;
Mail_Handler::send_mail($fromEmail, $subject_warnSender , $body_warnSender, $ticket->getTId(), NULL);
error_log("Email found that was a reply to a ticket, though send by an unknown email address to ".$group->getGroupEmail()."\n", 3, $MAIL_LOG_PATH);
2013-08-20 00:08:12 +00:00
2013-08-17 01:06:22 +00:00
}
2013-08-20 00:08:12 +00:00
return $ticket_id .".".time();
2013-08-12 21:56:58 +00:00
}else if($from != "FALSE"){
2013-08-12 21:56:58 +00:00
2013-08-17 01:06:22 +00:00
//if ticket_id isn't found, create a new ticket!
//if an existing email address mailed the ticket
//if not default group, then forward it by giving the $group->getSGroupId's param
$newTicketId = Ticket::create_Ticket($subject, $txt,1, $from, $from, $group->getSGroupId());
error_log("Email regarding new ticket found at:".$group->getGroupEmail()."\n", 3, $MAIL_LOG_PATH);
2013-08-20 00:08:12 +00:00
return $newTicketId .".".time();
2013-08-13 15:16:43 +00:00
}else{
//if it's a email that has nothing to do with ticketing, return 0;
error_log("Email found that isn't a reply or new ticket, at:".$group->getGroupEmail()."\n", 3, $MAIL_LOG_PATH);
return 0;
2013-08-12 21:56:58 +00:00
}
}
2013-08-10 11:59:36 +00:00
function decode_utf8($str) {
preg_match_all("/=\?UTF-8\?B\?([^\?]+)\?=/i",$str, $arr);
for ($i=0;$i<count($arr[1]);$i++){
$str=ereg_replace(ereg_replace("\?","\?",
$arr[0][$i]),base64_decode($arr[1][$i]),$str);
}
return $str;
}
2013-08-10 11:59:36 +00:00
function get_mime_type(&$structure) {
$primary_mime_type = array("TEXT", "MULTIPART","MESSAGE", "APPLICATION", "AUDIO","IMAGE", "VIDEO", "OTHER");
if($structure->subtype) {
return $primary_mime_type[(int) $structure->type] . '/' .$structure->subtype;
}
return "TEXT/PLAIN";
}
2013-08-10 11:59:36 +00:00
function get_part($stream, $msg_number, $mime_type, $structure = false, $part_number = false) {
if(!$structure) {
$structure = imap_fetchstructure($stream, $msg_number);
}
2013-08-10 11:59:36 +00:00
if($structure) {
if($mime_type == self::get_mime_type($structure)) {
2013-08-10 11:59:36 +00:00
if(!$part_number) {
$part_number = "1";
}
2013-08-10 11:59:36 +00:00
$text = imap_fetchbody($stream, $msg_number, $part_number);
if($structure->encoding == 3) {
return imap_base64($text);
} else if($structure->encoding == 4) {
return imap_qprint($text);
} else {
return $text;
}
2013-08-10 11:59:36 +00:00
}
if($structure->type == 1) /* multipart */ {
while(list($index, $sub_structure) = each($structure->parts)) {
if($part_number) {
$prefix = $part_number . '.';
} else {
$prefix = '';
}
$data = self::get_part($stream, $msg_number, $mime_type, $sub_structure,$prefix . ($index + 1));
2013-08-10 11:59:36 +00:00
if($data) {
return $data;
}
} // END OF WHILE
} // END OF MULTIPART
} // END OF STRUTURE
return false;
} // END OF FUNCTION
2013-08-20 00:08:12 +00:00
}