diff --git a/app/fax/app_config.php b/app/fax/app_config.php index 8567a0023d..dc9b788ffa 100644 --- a/app/fax/app_config.php +++ b/app/fax/app_config.php @@ -277,6 +277,14 @@ $apps[$x]['db'][$y]['fields'][$z]['type'] = "text"; $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ""; $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = "fax_send_greeting"; + $apps[$x]['db'][$y]['fields'][$z]['type'] = "text"; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ""; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = "fax_send_channels"; + $apps[$x]['db'][$y]['fields'][$z]['type'] = "numeric"; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ""; + $z++; //$apps[$x]['db'][$y]['fields'][$z]['name']['text'] = "fax_keep_local"; //$apps[$x]['db'][$y]['fields'][$z]['name']['deprecated'] = "fax_local"; //$apps[$x]['db'][$y]['fields'][$z]['type'] = "text"; @@ -499,4 +507,75 @@ $apps[$x]['db'][$y]['fields'][$z]['type'] = "numeric"; $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ""; + $y = 4; //table array index + $z = 0; //field array index + $apps[$x]['db'][$y]['table'] = 'v_fax_tasks'; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_uuid'; + $apps[$x]['db'][$y]['fields'][$z]['type']['pgsql'] = 'uuid'; + $apps[$x]['db'][$y]['fields'][$z]['type']['sqlite'] = 'text'; + $apps[$x]['db'][$y]['fields'][$z]['type']['mysql'] = 'char(36)'; + $apps[$x]['db'][$y]['fields'][$z]['key']['type'] = 'primary'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'fax_uuid'; + $apps[$x]['db'][$y]['fields'][$z]['type']['pgsql'] = 'uuid'; + $apps[$x]['db'][$y]['fields'][$z]['type']['sqlite'] = 'text'; + $apps[$x]['db'][$y]['fields'][$z]['type']['mysql'] = 'char(36)'; + $apps[$x]['db'][$y]['fields'][$z]['key']['type'] = 'foreign'; + $apps[$x]['db'][$y]['fields'][$z]['key']['reference']['table'] = 'v_fax'; + $apps[$x]['db'][$y]['fields'][$z]['key']['reference']['field'] = 'fax_uuid'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = 'FAX server primary key'; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_next_time'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'timestamp'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_lock_time'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'timestamp'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_fax_file'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'text'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_wav_file'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'text'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_uri'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'text'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_dial_string'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'text'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_dtmf'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'text'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_interrupted'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'text'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_status'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'numeric'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_no_answer_counter'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'numeric'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_no_answer_retry_counter'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'numeric'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_retry_counter'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'numeric'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; + $apps[$x]['db'][$y]['fields'][$z]['name'] = 'task_description'; + $apps[$x]['db'][$y]['fields'][$z]['type'] = 'text'; + $apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = ''; + $z++; ?> \ No newline at end of file diff --git a/app/fax/app_defaults.php b/app/fax/app_defaults.php index b3ab8cd98c..9efab50752 100644 --- a/app/fax/app_defaults.php +++ b/app/fax/app_defaults.php @@ -12,6 +12,13 @@ if ($domains_processed == 1) { $array[$x]['default_setting_description'] = 'Path to image/logo file displayed in the header of the cover sheet.'; $x++; $array[$x]['default_setting_category'] = 'fax'; + $array[$x]['default_setting_subcategory'] = 'cover_font'; + $array[$x]['default_setting_name'] = 'text'; + $array[$x]['default_setting_value'] = 'times'; + $array[$x]['default_setting_enabled'] = 'false'; + $array[$x]['default_setting_description'] = 'Font used to generate cover page. Can be full path to .ttf file or font name alredy installed.'; + $x++; + $array[$x]['default_setting_category'] = 'fax'; $array[$x]['default_setting_subcategory'] = 'cover_footer'; $array[$x]['default_setting_name'] = 'text'; $array[$x]['default_setting_value'] = "The information contained in this facsimile is intended for the sole confidential use of the recipient(s) designated above, and may contain confidential and legally privileged information. If you are not the intended recipient, you are hereby notified that the review, disclosure, dissemination, distribution, copying, duplication in any form, and taking of any action in regards to the contents of this document - except with respect to its direct delivery to the intended recipient - is strictly prohibited. Please notify the sender immediately and destroy this cover sheet and all attachments. If stored or viewed electronically, please permanently delete it from your system."; @@ -60,6 +67,55 @@ if ($domains_processed == 1) { $array[$x]['default_setting_enabled'] = 'true'; $array[$x]['default_setting_description'] = 'Keep the file after sending or receiving the fax.'; $x++; + $array[$x]['default_setting_category'] = 'fax'; + $array[$x]['default_setting_subcategory'] = 'send_mode'; + $array[$x]['default_setting_name'] = 'text'; + $array[$x]['default_setting_value'] = 'queue'; + $array[$x]['default_setting_enabled'] = 'false'; + $array[$x]['default_setting_description'] = ''; + $x++; + $array[$x]['default_setting_category'] = 'fax'; + $array[$x]['default_setting_subcategory'] = 'send_retry_limit'; + $array[$x]['default_setting_name'] = 'numeric'; + $array[$x]['default_setting_value'] = '5'; + $array[$x]['default_setting_enabled'] = 'true'; + $array[$x]['default_setting_description'] = 'Number of attempts to send fax (count only calls with answer)'; + $x++; + $array[$x]['default_setting_category'] = 'fax'; + $array[$x]['default_setting_subcategory'] = 'send_retry_interval'; + $array[$x]['default_setting_name'] = 'numeric'; + $array[$x]['default_setting_value'] = '15'; + $array[$x]['default_setting_enabled'] = 'true'; + $array[$x]['default_setting_description'] = 'Delay before we make next call after answered call'; + $x++; + $array[$x]['default_setting_category'] = 'fax'; + $array[$x]['default_setting_subcategory'] = 'send_no_answer_retry_limit'; + $array[$x]['default_setting_name'] = 'numeric'; + $array[$x]['default_setting_value'] = '3'; + $array[$x]['default_setting_enabled'] = 'true'; + $array[$x]['default_setting_description'] = 'Number of unanswered attempts in sequence'; + $x++; + $array[$x]['default_setting_category'] = 'fax'; + $array[$x]['default_setting_subcategory'] = 'send_no_answer_retry_interval'; + $array[$x]['default_setting_name'] = 'numeric'; + $array[$x]['default_setting_value'] = '30'; + $array[$x]['default_setting_enabled'] = 'true'; + $array[$x]['default_setting_description'] = 'Delay before we make next call after no answered call'; + $x++; + $array[$x]['default_setting_category'] = 'fax'; + $array[$x]['default_setting_subcategory'] = 'send_no_answer_limit'; + $array[$x]['default_setting_name'] = 'numeric'; + $array[$x]['default_setting_value'] = '3'; + $array[$x]['default_setting_enabled'] = 'true'; + $array[$x]['default_setting_description'] = 'Giveup reach the destination after this number of sequences'; + $x++; + $array[$x]['default_setting_category'] = 'fax'; + $array[$x]['default_setting_subcategory'] = 'send_no_answer_interval'; + $array[$x]['default_setting_name'] = 'numeric'; + $array[$x]['default_setting_value'] = '300'; + $array[$x]['default_setting_enabled'] = 'true'; + $array[$x]['default_setting_description'] = 'Delay before next call sequence'; + $x++; //get an array of the default settings $sql = "select * from v_default_settings "; $prep_statement = $db->prepare($sql); diff --git a/app/fax/app_languages.php b/app/fax/app_languages.php index 93ad7aa319..5d47714551 100644 --- a/app/fax/app_languages.php +++ b/app/fax/app_languages.php @@ -1111,6 +1111,10 @@ $text['label-accountcode']['de-at'] = "Account Code"; $text['label-accountcode']['ro'] = "Cod cont"; $text['label-accountcode']['he'] = "קוד חשבון"; +$text['label-fax_send_greeting']['en-us'] = "Greeting"; + +$text['label-fax_send_channels']['en-us'] = "Number of channels"; + $text['header-sent']['en-us'] = "Sent Faxes"; $text['header-sent']['es-cl'] = "Los Faxes Enviados"; $text['header-sent']['pt-pt'] = "Faxes Enviados"; diff --git a/app/fax/fax_edit.php b/app/fax/fax_edit.php index 27ffdc8ca4..e690d06739 100644 --- a/app/fax/fax_edit.php +++ b/app/fax/fax_edit.php @@ -135,8 +135,10 @@ else { } else { $forward_prefix = $forward_prefix.$fax_forward_number.'#'; //found } - $fax_local = check_str($_POST["fax_local"]); + $fax_local = check_str($_POST["fax_local"]); //! @todo check in database $fax_description = check_str($_POST["fax_description"]); + $fax_send_greeting = check_str($_POST["fax_send_greeting"]); + $fax_send_channels = check_str($_POST["fax_send_channels"]); } //delete the user from the fax users @@ -274,6 +276,8 @@ if (count($_POST)>0 && strlen($_POST["persistformvar"]) == 0) { if (strlen($fax_forward_number) > 0) { $sql .= "fax_forward_number, "; } + $sql .= "fax_send_greeting,"; + $sql .= "fax_send_channels,"; $sql .= "fax_description "; $sql .= ")"; $sql .= "values "; @@ -305,6 +309,9 @@ if (count($_POST)>0 && strlen($_POST["persistformvar"]) == 0) { if (strlen($fax_forward_number) > 0) { $sql .= "'$fax_forward_number', "; } + $sql .= (strlen($fax_send_greeting)==0?'NULL':"'$fax_send_greeting'") . ","; + $sql .= (strlen($fax_send_channels)==0?'NULL':"'$fax_send_channels'") . ","; + $sql .= "'$fax_description' "; $sql .= ")"; $db->exec(check_sql($sql)); @@ -345,9 +352,16 @@ if (count($_POST)>0 && strlen($_POST["persistformvar"]) == 0) { else { $sql .= "fax_forward_number = null, "; } + $tmp = strlen($fax_send_greeting)==0?'NULL':"'$fax_send_greeting'"; + $sql .= "fax_send_greeting = $tmp,"; + $tmp = strlen($fax_send_channels)==0?'NULL':"'$fax_send_channels'"; + $sql .= "fax_send_channels = $tmp,"; + $sql .= "fax_description = '$fax_description' "; + $sql .= "where domain_uuid = '".$_SESSION['domain_uuid']."' "; $sql .= "and fax_uuid = '$fax_uuid' "; + $db->exec(check_sql($sql)); unset($sql); } @@ -426,9 +440,14 @@ if (count($_POST)>0 && strlen($_POST["persistformvar"]) == 0) { $fax_caller_id_number = $row["fax_caller_id_number"]; $fax_forward_number = $row["fax_forward_number"]; $fax_description = $row["fax_description"]; + $fax_send_greeting = $row["fax_send_greeting"]; + $fax_send_channels = $row["fax_send_channels"]; } unset ($prep_statement); } + else{ + $fax_send_channels = 10; + } //replace the dash with a space $fax_name = str_replace("-", " ", $fax_name); @@ -667,6 +686,28 @@ if (count($_POST)>0 && strlen($_POST["persistformvar"]) == 0) { } } + echo "\n"; + echo "\n"; + echo " ".$text['label-fax_send_greeting']."\n"; + echo "\n"; + echo "\n"; + echo " \n"; + echo "
\n"; + echo " ".$text['description-fax_send_greeting']."\n"; + echo "\n"; + echo "\n"; + + echo "\n"; + echo "\n"; + echo " ".$text['label-fax_send_channels']."\n"; + echo "\n"; + echo "\n"; + echo " \n"; + echo "
\n"; + echo " ".$text['description-fax_send_channels']."\n"; + echo "\n"; + echo "\n"; + echo "\n"; echo "\n"; echo " ".$text['label-description']."\n"; @@ -677,7 +718,6 @@ if (count($_POST)>0 && strlen($_POST["persistformvar"]) == 0) { echo "".$text['description-info']."\n"; echo "\n"; echo "\n"; - } echo " \n"; diff --git a/app/fax/fax_emails.php b/app/fax/fax_emails.php index 3c615a8e75..234367e7b8 100644 --- a/app/fax/fax_emails.php +++ b/app/fax/fax_emails.php @@ -29,6 +29,7 @@ include "root.php"; require_once "resources/require.php"; require_once "resources/functions/object_to_array.php"; require_once "resources/functions/parse_attachments.php"; +require_once "resources/functions/parse_message.php"; require_once "resources/classes/text.php"; //get accounts to monitor @@ -55,6 +56,12 @@ if (sizeof($result) != 0) { $event_socket['password'] = $record['event_socket_password']; unset($sql, $prep_statement, $record); + $fax_send_mode_default = $_SESSION['fax']['send_mode']['text']; + if(strlen($fax_send_mode_default) == 0){ + $fax_send_mode_default = 'direct'; + } + $fax_cover_font_default = $_SESSION['fax']['cover_font']['text']; + foreach ($result as $row) { //get fax server and account connection details $fax_uuid = $row["fax_uuid"]; @@ -74,12 +81,23 @@ if (sizeof($result) != 0) { $fax_email_connection_mailbox = $row["fax_email_connection_mailbox"]; $fax_email_outbound_subject_tag = $row["fax_email_outbound_subject_tag"]; $fax_email_outbound_authorized_senders = $row["fax_email_outbound_authorized_senders"]; + $fax_send_greeting = $row["fax_send_greeting"]; //load default settings, then domain settings over top unset($_SESSION); $_SESSION = $default_settings; load_domain_settings($domain_uuid); + $fax_send_mode = $_SESSION['fax']['send_mode']['text']; + if(strlen($fax_send_mode) == 0){ + $fax_send_mode = $fax_send_mode_default; + } + + $fax_cover_font = $_SESSION['fax']['cover_font']['text']; + if(strlen($fax_cover_font) == 0){ + $fax_cover_font = $fax_cover_font_default; + } + //load event socket connection parameters $_SESSION['event_socket_ip_address'] = $event_socket['ip_address']; $_SESSION['event_socket_port'] = $event_socket['port']; @@ -159,22 +177,14 @@ if (sizeof($result) != 0) { else { $fax_numbers[] = $tmp; } - foreach ($fax_numbers as $index => $fax_number) { - $fax_numbers[$index] = preg_replace("~[^0-9]~", "", $fax_number); - if ($fax_numbers[$index] == '') { unset($fax_numbers[$index]); } - } unset($fax_subject); //clear so not on cover page //get email body (if any) for cover page - $fax_message = imap_fetchbody($connection, $email_id, '1.1', FT_UID); - $fax_message = strip_tags($fax_message); - $fax_message = trim($fax_message); + $fax_message = parse_message($connection, $email_id, FT_UID); if ($fax_message == '') { - $fax_message = imap_fetchbody($connection, $email_id, '1', FT_UID); $fax_message = strip_tags($fax_message); - $fax_message = trim($fax_message); + $fax_message = str_replace("\r\n\r\n","\r\n", $fax_message); } - $fax_message = str_replace("\r\n\r\n","\r\n", $fax_message); // set fax directory (used for pdf creation - cover and/or attachments) $fax_dir = $_SESSION['switch']['storage']['dir'].'/fax'.(($domain_name != '') ? '/'.$domain_name : null); @@ -200,8 +210,12 @@ if (sizeof($result) != 0) { } //send fax + $cwd = getcwd(); $included = true; require("fax_send.php"); + if($cwd){ + chdir($cwd); + } //reset variables unset($fax_numbers); diff --git a/app/fax/fax_send.php b/app/fax/fax_send.php index 315737f933..b50cbdbd91 100644 --- a/app/fax/fax_send.php +++ b/app/fax/fax_send.php @@ -84,21 +84,29 @@ if (!$included) { } foreach ($result as &$row) { //set database fields as variables + $fax_uuid = $row["fax_uuid"]; $fax_extension = $row["fax_extension"]; $fax_caller_id_name = $row["fax_caller_id_name"]; $fax_caller_id_number = $row["fax_caller_id_number"]; $fax_accountcode = $row["accountcode"]; + $fax_send_greeting = $row["fax_send_greeting"]; //limit to one row break; } unset ($prep_statement); + $fax_send_mode = $_SESSION['fax']['send_mode']['text']; + if(strlen($fax_send_mode) == 0){ + $fax_send_mode = 'direct'; + } } //set the fax directory $fax_dir = $_SESSION['switch']['storage']['dir'].'/fax'.((count($_SESSION["domains"]) > 1) ? '/'.$_SESSION['domain_name'] : null); + // set fax cover font to generate pdf + $fax_cover_font = $_SESSION['fax']['cover_font']['text']; } -else { +else{ require_once "resources/classes/EventSocket.php"; } @@ -122,6 +130,68 @@ if(!function_exists('gs_cmd')) { } } +if(!function_exists('fax_enqueue')) { + function fax_enqueue($fax_uuid, $fax_file, $wav_file, $fax_uri, $fax_dtmf, $dial_string){ + global $db, $db_type; + + $task_uuid = uuid(); + $dial_string .= "task_uuid='" . $task_uuid . "',"; + $description = ''; //! @todo add description + if ($db_type == "pgsql") { + $date_utc_now_sql = "NOW() at time zone 'utc'"; + } + if ($db_type == "mysql") { + $date_utc_now_sql = "UTC_TIMESTAMP()"; + } + if ($db_type == "sqlite") { + $date_utc_now_sql = "datetime('now')"; + } + $sql = <<prepare($sql); + $i = 0; + $stmt->bindValue(++$i, $task_uuid); + $stmt->bindValue(++$i, $fax_uuid); + $stmt->bindValue(++$i, $fax_file); + $stmt->bindValue(++$i, $wav_file); + $stmt->bindValue(++$i, $fax_uri); + $stmt->bindValue(++$i, $dial_string); + $stmt->bindValue(++$i, $fax_dtmf); + $stmt->bindValue(++$i, $description); + if ($stmt->execute()) { + $response = 'Enqueued'; + } + else{ + //! @todo log error + $response = 'Fail enqueue'; + var_dump($db->errorInfo()); + } + unset($stmt); + return $response; + } +} + +if(!function_exists('fax_split_dtmf')) { +function fax_split_dtmf(&$fax_number, &$fax_dtmf){ + $tmp = array(); + $fax_dtmf = ''; + if(preg_match('/^\s*(.*?)\s*\((.*)\)\s*$/', $fax_number, $tmp)){ + $fax_number = $tmp[1]; + $fax_dtmf = $tmp[2]; + } +} +} + //get the fax extension if (strlen($fax_extension) > 0) { //set the fax directories. example /usr/local/freeswitch/storage/fax/329/inbox @@ -171,14 +241,6 @@ if(!function_exists('gs_cmd')) { if (($_POST['action'] == "send")) { $fax_numbers = $_POST['fax_numbers']; - if (sizeof($fax_numbers) > 0) { - foreach ($fax_numbers as $index => $fax_number) { - $fax_numbers[$index] = preg_replace("~[^0-9]~", "", $fax_number); - if ($fax_numbers[$index] == '') { unset($fax_numbers[$index]); } - } - sort($fax_numbers); - } - $fax_uuid = check_str($_POST["id"]); $fax_caller_id_name = check_str($_POST['fax_caller_id_name']); $fax_caller_id_number = check_str($_POST['fax_caller_id_number']); @@ -200,6 +262,23 @@ if(!function_exists('gs_cmd')) { $continue = true; } +// cleanup numbers + if (isset($fax_numbers)) { + foreach ($fax_numbers as $index => $fax_number) { + fax_split_dtmf($fax_number, $fax_dtmf); + $fax_number = preg_replace("~[^0-9]~", "", $fax_number); + $fax_dtmf = preg_replace("~[^0-9Pp*#]~", "", $fax_dtmf); + if ($fax_number != ''){ + if ($fax_dtmf != '') {$fax_number .= " (" . $fax_dtmf . ")";} + $fax_numbers[$index] = $fax_number; + } + else{ + unset($fax_numbers[$index]); + } + } + sort($fax_numbers); + } + if ($continue) { //determine page size switch ($fax_page_size) { @@ -322,6 +401,19 @@ if(!function_exists('gs_cmd')) { $pdf -> setPrintFooter(false); $pdf -> SetMargins(0, 0, 0, true); + if(strlen($fax_cover_font) > 0){ + if(substr($fax_cover_font, -4) == '.ttf'){ + $pdf_font = TCPDF_FONTS::addTTFfont($fax_cover_font); + } + else{ + $pdf_font = $fax_cover_font; + } + } + + if(!$pdf_font){ + $pdf_font = 'times'; + } + //add blank page $pdf -> AddPage('P', array($page_width, $page_height)); @@ -329,9 +421,6 @@ if(!function_exists('gs_cmd')) { $x = 0; $y = 0; - // output grid - //showgrid($pdf); - //logo $display_logo = false; if (!isset($_SESSION['fax']['cover_logo']['text'])) { @@ -375,23 +464,23 @@ if(!function_exists('gs_cmd')) { //header if ($fax_header != '') { $pdf -> SetLeftMargin(0.5); - $pdf -> SetFont("times", "", 10); + $pdf -> SetFont($pdf_font, "", 10); $pdf -> Write(0.3, $fax_header); } //fax, cover sheet $pdf -> SetTextColor(0,0,0); - $pdf -> SetFont("times", "B", 55); + $pdf -> SetFont($pdf_font, "B", 55); $pdf -> SetXY($x + 4.55, $y + 0.25); $pdf -> Cell($x + 3.50, $y + 0.4, $text['label-fax-fax'], 0, 0, 'R', false, null, 0, false, 'T', 'T'); - $pdf -> SetFont("times", "", 12); + $pdf -> SetFont($pdf_font, "", 12); $pdf -> SetFontSpacing(0.0425); $pdf -> SetXY($x + 4.55, $y + 1.0); $pdf -> Cell($x + 3.50, $y + 0.4, $text['label-fax-cover-sheet'], 0, 0, 'R', false, null, 0, false, 'T', 'T'); $pdf -> SetFontSpacing(0); //field labels - $pdf -> SetFont("times", "B", 12); + $pdf -> SetFont($pdf_font, "B", 12); if ($fax_recipient != '' || sizeof($fax_numbers) > 0) { $pdf -> Text($x + 0.5, $y + 2.0, strtoupper($text['label-fax-recipient']).":"); } @@ -406,7 +495,7 @@ if(!function_exists('gs_cmd')) { } //field values - $pdf -> SetFont("times", "", 12); + $pdf -> SetFont($pdf_font, "", 12); $pdf -> SetXY($x + 2.0, $y + 1.95); if ($fax_recipient != '') { $pdf -> Write(0.3, $fax_recipient); @@ -446,7 +535,7 @@ if(!function_exists('gs_cmd')) { //message $pdf -> Rect($x + 0.5, $y + 3.4, 7.5, 6.25, 'D'); if ($fax_message != '') { - $pdf -> SetFont("times", "", 12); + $pdf -> SetFont($pdf_font, "", 12); $pdf -> SetXY($x + 0.75, $y + 3.65); $pdf -> MultiCell(7, 5.75, $fax_message, 0, 'L', false); } @@ -534,7 +623,7 @@ if(!function_exists('gs_cmd')) { } //preview, if requested - if ($_REQUEST['submit'] == $text['button-preview']) { + if (($_REQUEST['submit'] != '') && ($_REQUEST['submit'] == $text['button-preview'])) { unset($file_type); if (file_exists($dir_fax_temp.'/'.$fax_instance_uuid.'.pdf')) { $file_type = 'pdf'; @@ -599,29 +688,64 @@ if(!function_exists('gs_cmd')) { } //send the fax + $fax_file = $dir_fax_temp."/".$fax_instance_uuid.".tif"; + $common_dial_string = "for_fax=1,"; + $common_dial_string .= "accountcode='" . $fax_accountcode . "',"; + $common_dial_string .= "sip_h_X-accountcode='" . $fax_accountcode . "',"; + $common_dial_string .= "domain_uuid=" . $_SESSION["domain_uuid"] . ","; + $common_dial_string .= "domain_name=" . $_SESSION["domain_name"] . ","; + $common_dial_string .= "mailto_address='" . $mailto_address . "',"; + $common_dial_string .= "mailfrom_address='" . $mailfrom_address . "',"; + $common_dial_string .= "origination_caller_id_name='" . $fax_caller_id_name . "',"; + $common_dial_string .= "origination_caller_id_number='" . $fax_caller_id_number . "',"; + $common_dial_string .= "fax_ident='" . $fax_caller_id_number . "',"; + $common_dial_string .= "fax_header='" . $fax_caller_id_name . "',"; + $common_dial_string .= "fax_file='" . $fax_file . "',"; + foreach ($fax_numbers as $fax_number) { - $fp = event_socket_create($_SESSION['event_socket_ip_address'], $_SESSION['event_socket_port'], $_SESSION['event_socket_password']); - if ($fp) { - //prepare the fax command - $route_array = outbound_route_to_bridge($_SESSION['domain_uuid'], $fax_prefix.$fax_number); - $fax_file = $dir_fax_temp."/".$fax_instance_uuid.".tif"; - if (count($route_array) == 0) { - //send the internal call to the registered extension - $fax_uri = "user/".$fax_number."@".$_SESSION['domain_name']; - $t38 = ""; + $dial_string = $common_dial_string; + fax_split_dtmf($fax_number, $fax_dtmf); + + //prepare the fax command + $route_array = outbound_route_to_bridge($_SESSION['domain_uuid'], $fax_prefix . $fax_number); + + if (count($route_array) == 0) { + //send the internal call to the registered extension + $fax_uri = "user/".$fax_number."@".$_SESSION['domain_name']; + $t38 = ""; + } + else { + //send the external call + $fax_uri = $route_array[0]; + $t38 = "fax_enable_t38=true,fax_enable_t38_request=true,"; + } + + if ($fax_send_mode != 'queue') { + $dial_string .= $t38; + $dial_string .= "fax_uri=" . $fax_uri . ","; + $dial_string .= "fax_retry_attempts=1" . ","; + $dial_string .= "fax_retry_limit=20" . ","; + $dial_string .= "fax_retry_sleep=180" . ","; + $dial_string .= "fax_verbose=true" . ","; + $dial_string .= "fax_use_ecm=off" . ","; + $dial_string .= "api_hangup_hook='lua fax_retry.lua'"; + $dial_string = "{" . $dial_string . "}" . $fax_uri." &txfax('".$fax_file."')"; + + $fp = event_socket_create($_SESSION['event_socket_ip_address'], $_SESSION['event_socket_port'], $_SESSION['event_socket_password']); + if ($fp) { + $cmd = "api originate " . $dial_string; + // echo($cmd . "
\n"); + //send the command to event socket + $response = event_socket_request($fp, $cmd); + $response = str_replace("\n", "", $response); + $uuid = str_replace("+OK ", "", $response); } - else { - //send the external call - $fax_uri = $route_array[0]; - $t38 = "fax_enable_t38=true,fax_enable_t38_request=true,"; - } - $cmd = "api originate {for_fax=1,accountcode='".$fax_accountcode."',sip_h_X-accountcode='".$fax_accountcode."',domain_uuid=".$_SESSION["domain_uuid"].",domain_name=".$_SESSION["domain_name"].",mailto_address='".$mailto_address."',mailfrom_address='".$mailfrom_address."',origination_caller_id_name='".$fax_caller_id_name."',origination_caller_id_number='".$fax_caller_id_number."',fax_ident='".$fax_caller_id_number."',fax_header='".$fax_caller_id_name."',fax_uri=".$fax_uri.",fax_file='".$fax_file."',fax_retry_attempts=1,fax_retry_limit=20,fax_retry_sleep=180,fax_verbose=true,fax_use_ecm=off,".$t38."api_hangup_hook='lua fax_retry.lua'}".$fax_uri." &txfax('".$fax_file."')"; - //send the command to event socket - $response = event_socket_request($fp, $cmd); - $response = str_replace("\n", "", $response); - $uuid = str_replace("+OK ", "", $response); fclose($fp); } + else{ // enqueue + $wav_file = ''; //! @todo add custom message + $response = fax_enqueue($fax_uuid, $fax_file, $wav_file, $fax_uri, $fax_dtmf, $dial_string); + } } //wait for a few seconds diff --git a/app/fax/resources/functions/parse_message.php b/app/fax/resources/functions/parse_message.php new file mode 100644 index 0000000000..c2945e76b2 --- /dev/null +++ b/app/fax/resources/functions/parse_message.php @@ -0,0 +1,38 @@ +parts) && count($structure->parts)) { + for($i = 0; $i < count($structure->parts); $i++) { + $msg = ''; + $part = $structure->parts[$i]; + if($part->type == TYPETEXT){ + $msg = imap_fetchbody($connection, $message_number, $i+1, $option); + if($part->encoding == ENCBASE64){ + $msg = base64_decode($msg); + } + else if($part->encoding == ENCQUOTEDPRINTABLE){ + $msg = quoted_printable_decode($msg); + } + if($msg && $to_charset){ + $charset = ''; + if(isset($part->parameters) && count($part->parameters)) { + foreach($part->parameters as &$parameter){ + if($parameter->attribute == 'CHARSET') { + $charset = $parameter->value; + break; + } + } + } + if($charset){ + $msg = mb_convert_encoding($msg, $to_charset, $charset); + } + } + + if($msg){ + return $msg; + } + } + } + } +} diff --git a/resources/install/scripts/fax_queue/exec.lua b/resources/install/scripts/fax_queue/exec.lua new file mode 100644 index 0000000000..a47dc92148 --- /dev/null +++ b/resources/install/scripts/fax_queue/exec.lua @@ -0,0 +1,181 @@ +-- @usage without queue +-- api: originate {fax_file='',wav_file='',fax_dtmf=''}user/108@domain.local &lua(fax_queue/exec.lua) +-- @usage with queue task +-- api: originate {task_uuid=''}user/108@domain.local &lua(fax_queue/exec.lua) +-- @fax_dtmf +-- 0-9*# - dtmf symbols +-- @200 - dtmf duration in ms +-- p - pause 500 ms +-- P - pause 1000 ms +-- +-- example: pause 5 sec dial 008 pause 2 sec paly greeting +-- PPPPP008@300PP +-- + +require "resources.functions.config" +local log = require "resources.functions.log".fax_task + +-- If we handle queue task +local task_uuid = session:getVariable('task_uuid') +local task if task_uuid then + local Tasks = require "fax_queue.tasks" + task = Tasks.select_task(task_uuid) + if not task then + log.warningf("Can not found fax task: %q", tostring(task_uuid)) + return + end +end + +if task then + local str = 'Queue task :' + for k, v in pairs(task) do + str = str .. ('\n %q = %q'):format(k, v) + end + log.info(str) +else + log.info('Not queued task') +end + +local function empty(t) return (not t) or (#t == 0) end + +local function not_empty(t) if not empty(t) then return t end end + +local dtmf, wav_file, fax_file + +if task then + dtmf = not_empty(task.dtmf) + wav_file = not_empty(task.wav_file) or not_empty(task.greeting) + fax_file = not_empty(task.fax_file) +else + dtmf = not_empty(session:getVariable('fax_dtmf')) + wav_file = not_empty(session:getVariable('wav_file')) + fax_file = not_empty(session:getVariable('fax_file')) +end + +if not (wav_file or fax_file) then + log.warning("No fax or wav file") + return +end + +local function decode_dtmf(dtmf) + local r, sleep, seq = {} + dtmf:gsub('P', 'pp'):gsub('.', function(ch) + if ch == ';' or ch == ',' then + r[#r + 1] = sleep or seq + sleep, seq = nil + elseif ch == 'p' then + r[#r + 1] = seq + sleep = (sleep or 0) + 500 + seq = nil + else + r[#r + 1] = sleep + seq = (seq or '') .. ch + sleep = nil + end + end) + r[#r + 1] = sleep or seq + return r +end + +local function send_fax() + session:execute("txfax", fax_file) +end + +local function start_fax_detect(detect_duration) + if not tone_detect_cb then + function tone_detect_cb(s, type, obj, arg) + if type == "event" then + if obj:getHeader('Event-Name') == 'DETECTED_TONE' then + return "false" + end + end + end + end + + log.notice("Start detecting fax") + + detect_duration = detect_duration or 60000 + + session:setInputCallback("tone_detect_cb") + session:execute("tone_detect", "txfax 2100 r +" .. tostring(detect_duration) .. " set remote_fax_detected=txfax") + session:execute("tone_detect", "rxfax 1100 r +" .. tostring(detect_duration) .. " set remote_fax_detected=rxfax") + session:setVariable("sip_api_on_image", "uuid_break " .. session:getVariable("uuid") .. " all") +end + +local function stop_fax_detect() + session:unsetInputCallback() + session:execute("stop_tone_detect") + session:setVariable("sip_api_on_image", "") +end + +local function fax_deteced() + if session:getVariable('has_t38') == 'true' then + log.noticef('Detected t38') + session:setVariable('remote_fax_detected', 'txfax') + end + + if fax_file and session:getVariable('remote_fax_detected') then + log.noticef("Detected %s", session:getVariable('remote_fax_detected')) + if session:getVariable('remote_fax_detected') == 'txfax' then + send_fax() + else + log.warning('Remote fax try send fax') + end + return true + end +end + +local function check() + if not session:ready() then return false end + if fax_deteced() then return false end + return true +end + +local function task() + session:waitForAnswer(session) + + while not session:answered() do + if not session:ready() then return end + session:sleep(500) + end + + if not (session:ready() and session:answered()) then return end + + if fax_file and wav_file then + start_fax_detect() + end + + if dtmf then + dtmf = decode_dtmf(dtmf) + for _, element in ipairs(dtmf) do + if type(element) == 'number' then + session:streamFile("silence_stream://" .. tostring(element)) + else + session:execute("send_dtmf", element) + end + if not check() then return end + end + end + + if wav_file then + session:streamFile(wav_file) + if not check() then return end + end + + if fax_file then + if wav_file then + stop_fax_detect() + end + send_fax() + end +end + +log.noticef("START TASK") +log.notice("Fax:" .. tostring(fax_file)) +log.notice("Wav:" .. tostring(wav_file)) + +task() + +log.noticef("STOP TASK") +log.notice("Ready: " .. tostring(session:ready())) +log.notice("Answered: " .. tostring(session:answered())) diff --git a/resources/install/scripts/fax_queue/next.lua b/resources/install/scripts/fax_queue/next.lua new file mode 100644 index 0000000000..0067d0e9b4 --- /dev/null +++ b/resources/install/scripts/fax_queue/next.lua @@ -0,0 +1,69 @@ +require "resources.functions.config" + +require "resources.functions.sleep" +local log = require "resources.functions.log".next_fax_task +local Tasks = require "fax_queue.tasks" +local Esl = require "resources.functions.esl" + +local FAX_OPTIONS = { + "fax_use_ecm=false,fax_enable_t38=true,fax_enable_t38_request=true,fax_disable_v17=default"; + "fax_use_ecm=true,fax_enable_t38=true,fax_enable_t38_request=true,fax_disable_v17=false"; + "fax_use_ecm=true,fax_enable_t38=false,fax_enable_t38_request=false,fax_disable_v17=false"; + "fax_use_ecm=true,fax_enable_t38=true,fax_enable_t38_request=true,fax_disable_v17=true"; + "fax_use_ecm=false,fax_enable_t38=false,fax_enable_t38_request=false,fax_disable_v17=false"; +} + +local function next_task() + local task, err = Tasks.next_task() + + if not task then + if err then + log.noticef('Can not select next task: %s', tostring(err)) + else + log.notice("No task") + end + return + end + + local esl + local ok, err = pcall(function() + + for k, v in pairs(task) do + print(string.format(" `%s` => `%s`", tostring(k), tostring(v))) + end + + local mode = (task.retry_counter % #FAX_OPTIONS) + 1 + local dial_string = '{' .. + task.dial_string .. "api_hangup_hook='lua fax_queue/retry.lua'," .. + FAX_OPTIONS[mode] .. + '}' .. task.uri + + local originate = 'originate ' .. dial_string .. ' &lua(fax_queue/exec.lua)' + + log.notice(originate) + esl = assert(Esl.new()) + local ok, err = esl:api(originate) + log.notice(ok or err) + end) + + if esl then esl:close() end + + if not ok then + Tasks.release_task(task) + log.noticef("Error execute task: %s", tostring(err)) + end + + return true +end + +local function poll_once() + Tasks.cleanup_tasks() + while next_task() do + sleep(5000) + end + Tasks.release_db() +end + +return { + poll_once = poll_once; +} diff --git a/resources/install/scripts/fax_queue/retry.lua b/resources/install/scripts/fax_queue/retry.lua new file mode 100644 index 0000000000..f4744bce73 --- /dev/null +++ b/resources/install/scripts/fax_queue/retry.lua @@ -0,0 +1,346 @@ +-- include libraries + require "resources.functions.config"; + require "resources.functions.explode"; + require "resources.functions.split"; + require "resources.functions.count"; + + local log = require "resources.functions.log".fax_retry + local Database = require "resources.functions.database" + local Settings = require "resources.functions.lazy_settings" + local Tasks = require "fax_queue.tasks" + + local task_uuid = env:getHeader('task_uuid') + local task = Tasks.select_task(task_uuid) + if not task then + log.warningf("Can not find fax task: %q", tostring(task_uuid)) + return + end + +-- show all channel variables + if debug["fax_serialize"] then + log.noticef("info:\n%s", env:serialize()) + end + + local dbh = Database.new('system') + +-- Channel/FusionPBX variables + local uuid = env:getHeader("uuid") + local domain_uuid = env:getHeader("domain_uuid") or task.domain_uuid + local domain_name = env:getHeader("domain_name") or task.domain_name + local origination_caller_id_name = env:getHeader("origination_caller_id_name") or '000000000000000' + local origination_caller_id_number = env:getHeader("origination_caller_id_number") or '000000000000000' + local accountcode = env:getHeader("accountcode") + local duration = tonumber(env:getHeader("billmsec")) or 0 + local sip_to_user = env:getHeader("sip_to_user") + local bridge_hangup_cause = env:getHeader("bridge_hangup_cause") + local hangup_cause_q850 = tonumber(env:getHeader("hangup_cause_q850")) + local answered = duration > 0 + +-- fax variables + local fax_success = env:getHeader('fax_success') + local has_t38 = env:getHeader('has_t38') or 'false' + local t38_broken_boolean = env:getHeader('t38_broken_boolean') or '' + local fax_result_code = tonumber(env:getHeader('fax_result_code')) or 2 + local fax_result_text = env:getHeader('fax_result_text') or 'FS_NOT_SET' + local fax_ecm_used = env:getHeader('fax_ecm_used') or '' + local fax_local_station_id = env:getHeader('fax_local_station_id') or '' + local fax_document_transferred_pages = env:getHeader('fax_document_transferred_pages') or nil + local fax_document_total_pages = env:getHeader('fax_document_total_pages') or nil + local fax_image_resolution = env:getHeader('fax_image_resolution') or '' + local fax_image_size = env:getHeader('fax_image_size') or nil + local fax_bad_rows = env:getHeader('fax_bad_rows') or nil + local fax_transfer_rate = env:getHeader('fax_transfer_rate') or nil + local fax_v17_disabled = env:getHeader('fax_v17_disabled') or '' + local fax_ecm_requested = env:getHeader('fax_ecm_requested') or '' + local fax_remote_station_id = env:getHeader('fax_remote_station_id') or '' + + local fax_options = ("fax_use_ecm=%s,fax_enable_t38=%s,fax_enable_t38_request=%s,fax_disable_v17=%s"):format( + env:getHeader('fax_use_ecm') or '', + env:getHeader('fax_enable_t38') or '', + env:getHeader('fax_enable_t38_request') or '', + env:getHeader('fax_disable_v17') or '' + ) + +-- Fax task params + local fax_uri = env:getHeader("fax_uri") or task.uri + local fax_file = env:getHeader("fax_file") or task.fax_file + local wav_file = env:getHeader("wav_file") or task.wav_file + local fax_uuid = task.fax_uuid + +-- Email variables + local email_address = env:getHeader("mailto_address") + local from_address = env:getHeader("mailfrom_address") or email_address + local number_dialed = fax_uri:match("/([^/]-)%s*$") + local email_message_fail = "We are sorry the fax failed to go through. It has been attached. Please check the number "..number_dialed..", and if it was correct you might consider emailing it instead." + local email_message_success = "We are happy to report the fax was sent successfully. It has been attached for your records." + + log.noticef([[<<< CALL RESULT >>> + uuid: = '%s' + answered: = '%s' + fax_file: = '%s' + wav_file: = '%s' + fax_uri: = '%s' + sip_to_user: = '%s' + accountcode: = '%s' + origination_caller_id_name: = '%s' + origination_caller_id_number: = '%s' + mailfrom_address: = '%s' + mailto_address: = '%s' + hangup_cause_q850: = '%s' + fax_options = '%s' +]], + tostring(uuid) , + tostring(answered) , + tostring(fax_file) , + tostring(wav_file) , + tostring(fax_uri) , + tostring(sip_to_user) , + tostring(accountcode) , + tostring(origination_caller_id_name) , + tostring(origination_caller_id_number) , + tostring(from_address) , + tostring(email_address) , + tostring(hangup_cause_q850) , + fax_options +) + + if fax_success then + log.noticef([[<<< FAX RESULT >>> + fax_success = '%s' + has_t38 = '%s' + t38_broken_boolean = '%s' + fax_result_code = '%s' + fax_result_text = '%s' + fax_ecm_used = '%s' + fax_local_station_id = '%s' + fax_document_transferred_pages = '%s' + fax_document_total_pages = '%s' + fax_image_resolution = '%s' + fax_image_size = '%s' + fax_bad_rows = '%s' + fax_transfer_rate = '%s' + fax_v17_disabled = '%s' + fax_ecm_requested = '%s' + fax_remote_station_id = '%s' + '%s' +]], + fax_success , + has_t38 , + t38_broken_boolean , + fax_result_code , + fax_result_text , + fax_ecm_used , + fax_local_station_id , + fax_document_transferred_pages , + fax_document_total_pages , + fax_image_resolution , + fax_image_size , + fax_bad_rows , + fax_transfer_rate , + fax_v17_disabled , + fax_ecm_requested , + fax_remote_station_id , + '---------------------------------' + ) + end + +--get the values from the fax file + if not (fax_uuid and domain_name) then + local array = split(fax_file, "[\\/]+") + domain_name = domain_name or array[#array - 3] + local fax_extension = fax_extension or array[#array - 2] + + if not fax_uuid then + local sql = "SELECT fax_uuid FROM v_fax " + sql = sql .. "WHERE domain_uuid = '" .. domain_uuid .. "' " + sql = sql .. "AND fax_extension = '" .. fax_extension .. "' " + fax_uuid = dbh:first_value(sql); + end + end + +--get the domain_uuid using the domain name required for multi-tenant + if domain_name and not domain_uuid then + local sql = "SELECT domain_uuid FROM v_domains "; + sql = sql .. "WHERE domain_name = '" .. domain_name .. "' " + domain_uuid = dbh:first_value(sql) + end + + assert(domain_name and domain_uuid) + +--settings + local settings = Settings.new(dbh, domain_name, domain_uuid) + local keep_local = settings:get('fax', 'keep_local','boolean') + local storage_type = (keep_local == "false") and "" or settings:get('fax', 'storage_type', 'text') + +--be sure accountcode is not empty + if (accountcode == nil) then + accountcode = domain_name + end + + local function opt(v, default) + if v then return "'" .. v .. "'" end + return default or 'NULL' + end + + local function now_sql() + return (database["type"] == "sqlite") and "'"..os.date("%Y-%m-%d %X").."'" or "now()"; + end + +--add to fax logs + do + local fields = { + "fax_log_uuid"; + "domain_uuid"; + "fax_uuid"; + "fax_success"; + "fax_result_code"; + "fax_result_text"; + "fax_file"; + "fax_ecm_used"; + "fax_local_station_id"; + "fax_document_transferred_pages"; + "fax_document_total_pages"; + "fax_image_resolution"; + "fax_image_size"; + "fax_bad_rows"; + "fax_transfer_rate"; + "fax_retry_attempts"; + "fax_retry_limit"; + "fax_retry_sleep"; + "fax_uri"; + "fax_date"; + "fax_epoch"; + } + + local values = { + "'"..uuid .. "'"; + "'"..domain_uuid .. "'"; + opt(fax_uuid); + opt(fax_success); + opt(fax_result_code); + opt(fax_result_text); + opt(fax_file); + opt(fax_ecm_used); + opt(fax_local_station_id); + opt(fax_document_transferred_pages, "'0'"); + opt(fax_document_total_pages, "'0'"); + opt(fax_image_resolution); + opt(fax_image_size); + opt(fax_bad_rows); + opt(fax_transfer_rate); + opt(fax_retry_attempts); + opt(fax_retry_limit); + opt(fax_retry_sleep); + opt(fax_uri); + now_sql(); + "'"..os.time().."' "; + } + + local sql = "insert into v_fax_logs(" .. table.concat(fields, ",") .. ")" .. + "values(" .. table.concat(values, ",") .. ")" + + if (debug["sql"]) then + log.noticef("SQL: %s", sql); + end + + dbh:query(sql); + end + +-- add the fax files + if fax_success == "1" then + + if storage_type == "base64" then + --include the base64 function + require "resources.functions.base64"; + + --base64 encode the file + local f = io.open(fax_file, "rb"); + if not f then + log.waitng("Can not find file %s", fax_file) + storage_type = nil + else + local file_content = f:read("*all"); + f:close() + fax_base64 = base64.encode(file_content) + end + end + + -- build SQL + local sql do + sql = { + "insert into v_fax_files("; + "fax_file_uuid"; ","; + "fax_uuid"; ","; + "fax_mode"; ","; + "fax_destination"; ","; + "fax_file_type"; ","; + "fax_file_path"; ","; + "fax_caller_id_name"; ","; + "fax_caller_id_number"; ","; + "fax_date"; ","; + "fax_epoch"; ","; + "fax_base64"; ","; + "domain_uuid"; " "; + ") values ("; + opt(uuid); ","; + opt(fax_uuid); ","; + "'tx'"; ","; + opt(sip_to_user); ","; + "'tif'"; ","; + opt(fax_file); ","; + opt(origination_caller_id_name); ","; + opt(origination_caller_id_number); ","; + now_sql(); ","; + "'" .. os.time() .. "'"; ","; + opt(fax_base64); ","; + opt(domain_uuid); " "; + ")" + } + + sql = table.concat(sql, "\n"); + if (debug["sql"]) then + log.noticef("SQL: %s", sql); + end + end + + if storage_type == "base64" then + local db_type, db_cnn = split_first(database["system"], "://", true) + local luasql = require ("luasql." .. db_type); + local env = assert (luasql[db_type]()); + local dbh = env:connect(db_cnn); + dbh:execute(sql) + dbh:close() + env:close() + else + result = dbh:query(sql) + end + end + + if fax_success == "1" then + --Success + log.infof("RETRY STATS SUCCESS: GATEWAY[%s]", fax_options); + + if keep_local == "false" then + os.remove(fax_file); + end + + Tasks.remove_task(task) + end + + if fax_success ~= "1" then + if not answered then + log.noticef("no answer: %d", hangup_cause_q850) + else + if not fax_success then + log.noticef("Fax not detected: %s", fax_options) + else + log.noticef("fax fail %s", fax_options) + end + end + + Tasks.wait_task(task, answered, hangup_cause_q850) + if task.status ~= 0 then + Tasks.remove_task(task) + end + end + diff --git a/resources/install/scripts/fax_queue/tasks.lua b/resources/install/scripts/fax_queue/tasks.lua new file mode 100644 index 0000000000..bb09ffb295 --- /dev/null +++ b/resources/install/scripts/fax_queue/tasks.lua @@ -0,0 +1,251 @@ +local Database = require "resources.functions.database" +local Settings = require "resources.functions.lazy_settings" + +local db + +local date_utc_now_sql +local now_add_sec_sql + +if database.type == 'pgsql' then + date_utc_now_sql = "NOW() at time zone 'utc'" + now_add_sec_sql = "NOW() at time zone 'utc' + interval '%s second'" +elseif database.type == 'mysql' then + date_utc_now_sql = "UTC_TIMESTAMP()" + now_add_sec_sql = "DATE_ADD(UTC_TIMESTAMP(), INTERVAL %s SECOND)" +elseif database.type == 'sqlite' then + date_utc_now_sql = "datetime('now')" + now_add_sec_sql = "datetime('now', '%s seconds')" +else + error("unsupported database type: " .. database.type) +end + +-- Broken on FS 1.4 with native postgresql +-- Fixed on 1.6.0 +-- Also works with ODBC +local ignore_affected_rows = true +if dbh_affected_rows_broken ~= nil then + ignore_affected_rows = dbh_affected_rows_broken +end + +local Q850_TIMEOUT = { + [17] = 60; +} + +local select_task_common_sql = [[ +select + t1.task_uuid as uuid, + t1.fax_uuid as fax_uuid, + t3.domain_name, + t3.domain_uuid, + t1.task_status as status, + t1.task_uri as uri, + t1.task_dial_string as dial_string, + t1.task_dtmf as dtmf, + t1.task_fax_file as fax_file, + t1.task_wav_file as wav_file, + t1.task_no_answer_counter as no_answer_counter, + t1.task_no_answer_retry_counter as no_answer_retry_counter, + t1.task_retry_counter as retry_counter, + t2.fax_send_greeting as greeting +from v_fax_tasks t1 + inner join v_fax t2 on t2.fax_uuid = t1.fax_uuid + inner join v_domains t3 on t2.domain_uuid = t3.domain_uuid +where t1.task_interrupted <> 'true' +]] + +local next_task_sql = select_task_common_sql .. [[ +and t1.task_status = 0 and t1.task_next_time < ]] .. date_utc_now_sql .. [[ +and t2.fax_send_channels > (select count(*) from v_fax_tasks as tasks + where tasks.fax_uuid = t1.fax_uuid and + tasks.task_status > 0 and tasks.task_status <= 2 +) +order by t1.task_next_time +]] + +local select_task_sql = select_task_common_sql .. "and t1.task_uuid='%s'" + +local aquire_task_sql = [[ + update v_fax_tasks set task_status = 1, task_lock_time = ]] .. date_utc_now_sql .. [[ + where task_uuid = '%s' and task_status = 0 +]] + +local wait_task_sql = [[ + update v_fax_tasks + set task_status = %s, + task_lock_time = NULL, + task_no_answer_counter = %s, + task_no_answer_retry_counter = %s, + task_retry_counter = %s, + task_next_time = ]] .. now_add_sec_sql .. [[ + where task_uuid = '%s' +]] + +local remove_task_task_sql = [[ + delete from v_fax_tasks + where task_uuid = '%s' +]] + +local release_task_sql = [[ + update v_fax_tasks + set task_status = 0, task_lock_time = NULL, + task_next_time = ]] .. now_add_sec_sql .. [[ + where task_uuid = '%s' +]] + +local release_stuck_tasks_sql = [[ + update v_fax_tasks + set task_status = 0, task_lock_time = NULL, + task_next_time = ]] .. date_utc_now_sql .. [[ + where task_lock_time < ]] .. now_add_sec_sql:format('-3600') .. [[ +]] + +local remove_finished_tasks_sql = [[ + delete from v_fax_tasks where task_status > 3 +]] + +local function get_db() + if not db then + db = assert(Database.new('system')) + end + return db +end + +local function next_task() + local db = get_db() + + while true do + local task, err = db:first_row(next_task_sql) + if not task then return nil, err end + local ok, err = db:query( aquire_task_sql:format(task.uuid) ) + if not ok then return nil, err end + local rows = db:affected_rows() + if ignore_affected_rows then + rows = 1 + end + if rows == 1 then + task.no_answer_counter = tonumber(task.no_answer_counter) + task.no_answer_retry_counter = tonumber(task.no_answer_retry_counter) + task.retry_counter = tonumber(task.retry_counter) + return task + end + end +end + +local function select_task(task_uuid) + local db = get_db() + + local task, err = db:first_row(select_task_sql:format(task_uuid)) + if not task then return nil, err end + + task.no_answer_counter = tonumber(task.no_answer_counter) + task.no_answer_retry_counter = tonumber(task.no_answer_retry_counter) + task.retry_counter = tonumber(task.retry_counter) + + return task +end + +local function wait_task(task, answered, q850) + local db = get_db() + + local interval = 30 + + local settings = Settings.new(db, task.domain_name, task.domain_uuid) + task.status = 0 + + if not answered then + interval = Q850_TIMEOUT[q850 or 17] or interval + end + + if not answered then + local fax_send_no_answer_retry_limit = tonumber(settings:get('fax', 'send_no_answer_retry_limit', 'numeric')) or 0 + task.no_answer_retry_counter = task.no_answer_retry_counter + 1 + + if task.no_answer_retry_counter >= fax_send_no_answer_retry_limit then + task.no_answer_retry_counter = 0 + task.no_answer_counter = task.no_answer_counter + 1 + local fax_send_no_answer_limit = tonumber(settings:get('fax', 'send_no_answer_limit', 'numeric')) or 0 + if task.no_answer_counter >= fax_send_no_answer_limit then + task.status = 4 + else + interval = tonumber(settings:get('fax', 'send_no_answer_interval', 'numeric')) or interval + end + else + interval = tonumber(settings:get('fax', 'send_no_answer_retry_interval', 'numeric')) or interval + end + else + task.retry_counter = task.retry_counter + 1 + local fax_send_retry_limit = tonumber(settings:get('fax', 'send_retry_limit', 'numeric')) or 0 + + if task.retry_counter >= fax_send_retry_limit then + task.status = 4 + else + interval = tonumber(settings:get('fax', 'send_retry_interval', 'numeric')) or interval + task.task_seq_call_counter = 0 + end + end + + local sql = wait_task_sql:format( + tostring(task.status), + tostring(task.no_answer_counter), + tostring(task.no_answer_retry_counter), + tostring(task.retry_counter), + tostring(interval), + task.uuid + ) + + print(sql) + + local ok, err = db:query( sql ) + + if not ok then return nil, err end + + return task +end + +local function remove_task(task) + local db = get_db() + + local sql = remove_task_task_sql:format(task.uuid) + local ok, err = db:query( sql ) + if not ok then return nil, err end + return db:affected_rows() +end + +local function release_task(task) + local db = get_db() + + local interval = 30 + + local sql = release_task_sql:format( + tostring(interval), + task.uuid + ) + + local ok, err = db:query( sql ) + + if not ok then return nil, err end + + return task +end + +local function cleanup_tasks() + local db = get_db() + + db:query(release_stuck_tasks_sql) + db:query(remove_finished_tasks_sql) +end + +return { + release_db = function() + if db then + db:release() + db = nil + end + end; + next_task = next_task; + wait_task = wait_task; + select_task = select_task; + remove_task = remove_task; + release_task = release_task; + cleanup_tasks = cleanup_tasks; +} diff --git a/resources/install/scripts/fax_queue_monitor.lua b/resources/install/scripts/fax_queue_monitor.lua new file mode 100644 index 0000000000..1f4371d2b7 --- /dev/null +++ b/resources/install/scripts/fax_queue_monitor.lua @@ -0,0 +1,42 @@ + local sleep_interval = 60; + +--include config.lua + require "resources.functions.config"; + +--general functions + require "resources.functions.file_exists"; + require "resources.functions.mkdir"; + require "resources.functions.sleep"; + + local log = require "resources.functions.log".fax_queue_monitor + local Next = require "fax_queue.next" + + mkdir(scripts_dir .. "/run"); + +--define the run file + local run_file = scripts_dir .. "/run/fax_queue.tmp"; + +--used to stop the lua service + local file = assert(io.open(run_file, "w")); + file:write("remove this file to stop the script"); + file:close() + + log.notice("Start") + + while true do + local ok, err = pcall(function() + Next.poll_once() + end) + + if not ok then + log.errf("fail poll queue: %s", tostring(err)) + end + + if not file_exists(run_file) then + break; + end + + sleep(sleep_interval * 1000) + end + + log.notice("Stop") diff --git a/resources/install/scripts/fax_queue_poll_once.lua b/resources/install/scripts/fax_queue_poll_once.lua new file mode 100644 index 0000000000..c42ee62c72 --- /dev/null +++ b/resources/install/scripts/fax_queue_poll_once.lua @@ -0,0 +1 @@ +require "fax_queue.next".poll_once() \ No newline at end of file diff --git a/resources/install/scripts/resources/functions/cache.lua b/resources/install/scripts/resources/functions/cache.lua index 06548af1cd..6d121eb995 100644 --- a/resources/install/scripts/resources/functions/cache.lua +++ b/resources/install/scripts/resources/functions/cache.lua @@ -8,7 +8,13 @@ require "resources.functions.trim"; -local api = api or freeswitch.API(); +local api = api +if (not api) and freeswitch then api = freeswitch.API() else +api = {} +function api:execute() + return '-ERR UNSUPPORTTED' +end +end local function send_event(action, key) local event = freeswitch.Event("MEMCACHE", action); diff --git a/resources/install/scripts/resources/functions/database.lua b/resources/install/scripts/resources/functions/database.lua index f8939126ff..17abe280ba 100644 --- a/resources/install/scripts/resources/functions/database.lua +++ b/resources/install/scripts/resources/functions/database.lua @@ -1,115 +1,190 @@ require 'resources.functions.config' -require 'resources.functions.file_exists' -require 'resources.functions.database_handle' -local unpack = unpack or table.unpack +----------------------------------------------------------- +local OdbcDatabase = {} if not freeswitch then +OdbcDatabase.__index = OdbcDatabase -local Database = {} do +local odbc = require "odbc.dba" -Database.__index = Database +function OdbcDatabase.new(name) + local self = setmetatable({}, OdbcDatabase) -function Database.new(name) - local dbh = assert(name) - if type(name) == 'string' then - if name == 'switch' and file_exists(database_dir.."/core.db") then - dbh = freeswitch.Dbh("sqlite://"..database_dir.."/core.db") - else - dbh = database_handle(name) - end - end - assert(dbh:connected()) + local connection_string = assert(database[name]) - local self = setmetatable({ - _dbh = dbh; - }, Database) + local typ, dsn, user, password = connection_string:match("^(.-)://(.-):(.-):(.-)$") + assert(typ == 'odbc', "unsupported connection string:" .. connection_string) - return self + self._dbh = odbc.Connect(dsn, user, password) + + return self end -function Database:query(sql, fn) - if (fn == nil) then - return self._dbh:query(sql) - else - return self._dbh:query(sql, fn) - end +function OdbcDatabase:query(sql, fn) + self._rows_affected = nil + if fn then + return self._dbh:neach(sql, function(row) + local o = {} + for k, v in pairs(row) do + if v == odbc.NULL then + o[k] = nil + else + o[k] = tostring(v) + end + end + return fn(o) + end) + end + local ok, err = self._dbh:exec(sql) + if not ok then return nil, err end + self._rows_affected = ok + return self._rows_affected +end + +function OdbcDatabase:affected_rows() + return self._rows_affected; +end + +function OdbcDatabase:release() + if self._dbh then + self._dbh:destroy() + self._dbh = nil + end +end + +function OdbcDatabase:connected() + return self._dbh and self._dbh:connected() +end + +end +----------------------------------------------------------- + +----------------------------------------------------------- +local FsDatabase = {} if freeswitch then + +require "resources.functions.file_exists" +require "resources.functions.database_handle" + +FsDatabase.__index = FsDatabase + +function FsDatabase.new(name) + local dbh = assert(name) + if type(name) == 'string' then + if name == 'switch' and file_exists(database_dir.."/core.db") then + dbh = freeswitch.Dbh("sqlite://"..database_dir.."/core.db") + else + dbh = database_handle(name) + end + end + assert(dbh:connected()) + + local self = setmetatable({ + _dbh = dbh; + }, FsDatabase) + + return self +end + +function FsDatabase:query(sql, fn) + if fn then + return self._dbh:query(sql, fn) + end + return self._dbh:query(sql) +end + +function FsDatabase:affected_rows() + if self._dbh then + return self._dbh:affected_rows() + end +end + +function FsDatabase:release() + if self._dbh then + self._dbh:release() + self._dbh = nil + end +end + +function FsDatabase:connected() + return self._dbh and self._dbh:connected() +end + +end +----------------------------------------------------------- + +----------------------------------------------------------- +local Database = {} do +Database.__index = Database +Database.__base = freeswitch and FsDatabase or OdbcDatabase +Database = setmetatable(Database, Database.__base) + +function Database.new(...) + local self = Database.__base.new(...) + setmetatable(self, Database) + return self end function Database:first_row(sql) - local result - local ok, err = self:query(sql, function(row) - result = row - return 1 - end) - if not ok then return nil, err end - return result + local result + local ok, err = self:query(sql, function(row) + result = row + return 1 + end) + if not ok then return nil, err end + return result end function Database:first_value(sql) - local result, err = self:first_row(sql) - if not result then return nil, err end - local k, v = next(result) - return v + local result, err = self:first_row(sql) + if not result then return nil, err end + local k, v = next(result) + return v end function Database:first(sql, ...) - local result, err = self:first_row(sql) - if not result then return nil, err end - local t, n = {}, select('#', ...) - for i = 1, n do - t[i] = result[(select(i, ...))] - end - return unpack(t, 1, n) + local result, err = self:first_row(sql) + if not result then return nil, err end + local t, n = {}, select('#', ...) + for i = 1, n do + t[i] = result[(select(i, ...))] + end + return unpack(t, 1, n) end function Database:fetch_all(sql) - local result = {} - local ok, err = self:query(sql, function(row) - result[#result + 1] = row - end) - if not ok then return nil, err end - return result + local result = {} + local ok, err = self:query(sql, function(row) + result[#result + 1] = row + end) + if (not ok) and err then return nil, err end + return result end -function Database:release(sql) - if self._dbh then - self._dbh:release() - self._dbh = nil - end -end +function Database.__self_test__(...) + local db = Database.new(...) + assert(db:connected()) -function Database:connected(sql) - return self._dbh and self._dbh:connected() -end + assert("1" == db:first_value("select 1 as v union all select 2 as v")) -function Database.__self_test__(name) - local db = Database.new(name or 'system') - assert(db:connected()) + local t = assert(db:first_row("select '1' as v union all select '2' as v")) + assert(t.v == "1") - assert("1" == db:first_value("select 1 as v union all select 2 as v")) + t = assert(db:fetch_all("select '1' as v union all select '2' as v")) + assert(#t == 2) + assert(t[1].v == "1") + assert(t[2].v == "2") - local t = assert(db:first_row("select 1 as v union all select 2 as v")) - assert(t.v == "1") + local a, b = assert(db:first("select '1' as b, '2' as a", 'a', 'b')) + assert(a == "2") + assert(b == "1") - t = assert(db:fetch_all("select 1 as v union all select 2 as v")) - assert(#t == 2) - assert(t[1].v == "1") - assert(t[2].v == "2") + -- assert(nil == db:first_value("some non sql query")) - local a, b = assert(db:first("select 1 as b, 2 as a", 'a', 'b')) - assert(a == "2") - assert(b == "1") - - -- assert(nil == db:first_value("some non sql query")) - - db:release() - assert(not db:connected()) - print(" * databse - OK!") + db:release() + assert(not db:connected()) + print(" * databse - OK!") end end - --- if debug.self_test then --- Database.__self_test__() --- end +----------------------------------------------------------- return Database \ No newline at end of file diff --git a/resources/install/scripts/resources/functions/esl.lua b/resources/install/scripts/resources/functions/esl.lua new file mode 100644 index 0000000000..fcd4898754 --- /dev/null +++ b/resources/install/scripts/resources/functions/esl.lua @@ -0,0 +1,159 @@ +local function class(base) + local t = base and setmetatable({}, base) or {} + t.__index = t + t.__class = t + t.__base = base + + function t.new(...) + local o = setmetatable({}, t) + if o.__init then + if t == ... then -- we call as Class:new() + return o:__init(select(2, ...)) + else -- we call as Class.new() + return o:__init(...) + end + end + return o + end + + return t +end + +local EventSocket = class() do + +if not freeswitch then + +local socket = require "socket" +local ESLParser = require "lluv.esl".ESLParser +local split_status = require "lluv.esl.utils".split_status +local Database = require "resources.functions.database" + +local EOL = '\n' + +local host, port, auth + +function EventSocket:__init() + if not host then + local db = Database.new('system') + local settings, err = db:first_row("select event_socket_ip_address, event_socket_port, event_socket_password from v_settings") + if not settings then return nil, err end + host, port, auth = settings.event_socket_ip_address, settings.event_socket_port, settings.event_socket_password + end + + return self:_connect(host, port, auth) +end + +function EventSocket:_connect(host, port, password) + local err + self._cnn, err = socket.connect(host, port) + if not self._cnn then return nil, err end + + self._cnn:settimeout(1) + + self._parser = ESLParser.new() + local auth + while true do + local event + event, err = self:_recv_event() + if not event then break end + + local ct = event:getHeader('Content-Type') + if ct == 'auth/request' then + self._cnn:send('auth ' .. password .. EOL .. EOL) + elseif ct == 'command/reply' then + local reply = event:getHeader('Reply-Text') + if reply then + local ok, status, msg = split_status(reply) + if ok then auth = true else err = msg end + else + err = 'invalid response' + end + break + end + end + + if not auth then + self._cnn:close() + self._cnn = nil + return nil, err + end + + return self +end + +function EventSocket:_recv_event() + local event, err = self._parser:next_event() + + while event == true do + local str, rst + str, err, rst = self._cnn:receive("*l") + if str then self._parser:append(str):append(EOL) end + if rst then self._parser:append(rst) end + if err and err ~= 'timeout' then + break + end + event = self._parser:next_event() + end + + if (not event) or (event == true) then + return nil, err + end + + return event +end + +function EventSocket:_request(cmd) + if not self._cnn then return nil, 'closed' end + + for str in (cmd .. '\n'):gmatch("(.-)\n") do + self._cnn:send(str .. EOL) + end + self._cnn:send(EOL) + + return self:_recv_event() +end + +function EventSocket:api(cmd) + local event, err = self:_request('api ' .. cmd) + if not event then return nil, err end + local body = event:getBody() + if body then return body end + return event:getReply() +end + +function EventSocket:close() + if self._cnn then + self._cnn:close() + self._cnn = nil + end +end + +end + +if freeswitch then + +local api + +function EventSocket:__init() + self._api = api or freeswitch.API() + api = self._api + return self +end + +function EventSocket:api(cmd) + local result = self._api:executeString(cmd) + if result and result:sub(1, 4) == '-ERR' then + return nil, result:sub(5) + end + return result +end + +function EventSocket:close() + self._api = nil +end + +end + +end + +return EventSocket diff --git a/resources/install/scripts/resources/functions/lazy_settings.lua b/resources/install/scripts/resources/functions/lazy_settings.lua new file mode 100644 index 0000000000..3d3b72b342 --- /dev/null +++ b/resources/install/scripts/resources/functions/lazy_settings.lua @@ -0,0 +1,172 @@ +-- -- Global settings +-- local settings = Settings.new('system') +-- print(settings:get('switch', 'base', 'dir')) +-- +-- Domain settings (to `fax_retry.lua`) +-- local Settings = require "resources.functions.settings" +-- local settings = Settings.new(dbh, domain_name, domain_uuid) +-- storage_type = settings:get('fax', 'storage_type', 'text') or '' +-- storage_path = settings:get('fax', 'storage_path', 'text') or '' +-- storage_path = storage_path +-- :gsub("${domain_name}", domain_name) +-- :gsub("${voicemail_id}", voicemail_id) +-- :gsub("${voicemail_dir}", voicemail_dir) + +local Database = require "resources.functions.database" +local cache = require "resources.functions.cache" +require "resources.functions.split" + +----------------------------------------------------------- +local Settings = {} do +Settings.__index = Settings + +local NONE = '15783958-912c-4893-8866-4ccd1ca73c6e' + +local function append(t, v) + t[#t+1] = v + return t +end + +local function append_setting(array, category, subcategory, name, value) + --add the category array + if not array[category] then + array[category] = {} + end + + --add the subcategory array + if not array[category][subcategory] then + array[category][subcategory] = {} + end + + --set the name and value + if (name == "array") then + if not array[category][subcategory][name] then + array[category][subcategory][name] = {} + end + append(array[category][subcategory][name], value); + elseif value ~= nil then + array[category][subcategory][name] = value; + end +end + +function Settings.new(db, domain_name, domain_uuid) + local self = setmetatable({}, Settings) + self._array = {} + self._db = db + self._domain_name = domain_name + self._domain_uuid = domain_uuid + + return self +end + +function Settings:_cache_key(category, subcategory, name) + return 'setting:' .. (self._domain_name or '') .. ':' .. category .. ':' .. subcategory .. ':' .. name +end + +function Settings:set(category, subcategory, name, value) + append_setting(self._array, category, subcategory, name, value) + return self +end + +function Settings:get(category, subcategory, name) + local a = self._array + local v = a[category] and a[category][subcategory] and a[category][subcategory][name] + if v == NONE then return nil end + if v ~= nil then return v end + + local key = self:_cache_key(category, subcategory, name) + + v = cache.get(key) + if v then + if v ~= NONE and name == 'array' then + v = split(v, '/+/', true) + end + self:set(category, subcategory, name, v) + if v == NONE then return nil end + return v + end + + return self:_load(category, subcategory, name) +end + +function Settings:_load(category, subcategory, name) + local domain_uuid = self._domain_uuid + local db = self._db + if type(self._db) == 'string' then + db = Database.new(self._db) + end + + local found = false + --get the domain settings + if domain_uuid then + sql = "SELECT domain_setting_uuid,domain_setting_category,domain_setting_subcategory,domain_setting_name,domain_setting_value " + sql = sql .. "FROM v_domain_settings "; + sql = sql .. "WHERE domain_uuid = '" .. domain_uuid .. "'"; + sql = sql .. "AND domain_setting_enabled = 'true' "; + sql = sql .. "AND domain_setting_category = '" .. category .."'"; + sql = sql .. "AND domain_setting_subcategory = '" .. subcategory .. "'"; + sql = sql .. "AND domain_setting_name = '" .. name .. "'"; + sql = sql .. "AND domain_setting_value is not null "; + sql = sql .. "ORDER BY domain_setting_category, domain_setting_subcategory ASC "; + + db:query(sql, function(row) + found = true; + self:set( + row.domain_setting_category, + row.domain_setting_subcategory, + row.domain_setting_name, + row.domain_setting_value + ) + end) + end + + if not found then + local sql = "SELECT default_setting_uuid,default_setting_category,default_setting_subcategory,default_setting_name,default_setting_value " + sql = sql .. "FROM v_default_settings "; + sql = sql .. "WHERE default_setting_enabled = 'true' "; + sql = sql .. "AND default_setting_category = '" .. category .."'"; + sql = sql .. "AND default_setting_subcategory = '" .. subcategory .. "'"; + sql = sql .. "AND default_setting_name = '" .. name .. "'"; + sql = sql .. "AND default_setting_value is not null "; + sql = sql .. "ORDER BY default_setting_category, default_setting_subcategory ASC"; + + db:query(sql, function(row) + found = true; + self:set( + row.default_setting_category, + row.default_setting_subcategory, + row.default_setting_name, + row.default_setting_value + ) + end) + end + + if not found then + self:set(category, subcategory, name, NONE) + end + + local a = self._array + local v = a[category] and a[category][subcategory] and a[category][subcategory][name] + + if cache.support() then + local key = self:_cache_key(category, subcategory, name) + local value = v + if v ~= NONE and name == 'array' then + value = table.concat(v, '/+/') + end + local exp = expire and expire["settings"] or 3600 + cache.set(key, value, exp) + end + + if type(self._db) == 'string' then + db:release() + end + + if v == NONE then return nil end + return v +end + +end +----------------------------------------------------------- + +return Settings diff --git a/resources/install/scripts/resources/functions/log.lua b/resources/install/scripts/resources/functions/log.lua index b6cb59652b..b88818447b 100644 --- a/resources/install/scripts/resources/functions/log.lua +++ b/resources/install/scripts/resources/functions/log.lua @@ -3,9 +3,14 @@ -- log.noticef("%s %s", "hello", "world") -- -- log if debug.SQL or debug.xml_handler.SQL then -- log.tracef("SQL", "SQL is %s", sql) - -local function log(name, level, msg) - freeswitch.consoleLog(level, "[" .. name .. "] " .. msg .. "\n") +local log if freeswitch then + log = function (name, level, msg) + freeswitch.consoleLog(level, "[" .. name .. "] " .. msg .. "\n") + end +else + log = function (name, level, msg) + print(os.date("%Y-%m-%d %X") .. '[' .. level:upper() .. '] [' .. name .. '] ' .. msg) + end end local function logf(name, level, ...) diff --git a/resources/install/scripts/resources/functions/sleep.lua b/resources/install/scripts/resources/functions/sleep.lua new file mode 100644 index 0000000000..e7ace57abd --- /dev/null +++ b/resources/install/scripts/resources/functions/sleep.lua @@ -0,0 +1,15 @@ +if freeswitch then + +function sleep(ms) + freeswitch.msleep(ms) +end + +else + +local socket = require "socket" + +function sleep(ms) + socket.sleep(ms/1000) +end + +end diff --git a/resources/install/scripts/resources/functions/split.lua b/resources/install/scripts/resources/functions/split.lua new file mode 100644 index 0000000000..c46e0cad0b --- /dev/null +++ b/resources/install/scripts/resources/functions/split.lua @@ -0,0 +1,27 @@ +function split(str, sep, plain) + local b, res = 1, {} + while b <= #str do + local e, e2 = string.find(str, sep, b, plain) + if e then + res[#res + 1] = string.sub(str, b, e-1) + b = e2 + 1 + else + res[#res + 1] = string.sub(str, b) + break + end + end + return res +end + +function split_first(str, sep, plain) + local e, e2 = string.find(str, sep, nil, plain) + if e then + return string.sub(str, 1, e - 1), string.sub(str, e2 + 1) + end + return str +end + +local unpack = unpack or table.unpack + +function usplit(...) return unpack(split(...)) end + diff --git a/secure/fax_to_email.php b/secure/fax_to_email.php index 6972b225b9..6a184b001a 100644 --- a/secure/fax_to_email.php +++ b/secure/fax_to_email.php @@ -37,6 +37,266 @@ if (defined('STDIN')) { //echo "$document_root is document_root\n"; } +if (stristr(PHP_OS, 'WIN')) { $IS_WINDOWS = true; } else { $IS_WINDOWS = false; } + +if(!function_exists('exec_in_dir')) { + function exec_in_dir($dir, $cmd, &$ok){ + $args = func_get_args(); + $cwd = getcwd(); + chdir($dir); + $output = array(); + $ret = 0; + $result = exec($cmd, $output, $ret); + if($cwd) + chdir($cwd); + $ok = ($ret == 0); + return join($output, "\n"); + } +} + +if(!function_exists('correct_path')) { + function correct_path($p) { + global $IS_WINDOWS; + if ($IS_WINDOWS) { + return str_replace('/', '\\', $p); + } + return $p; + } +} + +if(!function_exists('path_join')) { + function path_join() { + $args = func_get_args(); + $paths = array(); + foreach ($args as $arg) { + $paths = array_merge($paths, (array)$arg); + } + + $prefix = null; + foreach($paths as &$path) { + if($prefix === null && strlen($path) > 0) { + if(substr($path, 0, 1) == '/') $prefix = '/'; + else $prefix = ''; + } + $path = trim( $path, '/' ); + } + + if($prefix === null){ + return ''; + } + + $paths = array_filter($paths); + + return $prefix . join('/', $paths); + } +} + +if(!function_exists('tiff2pdf')) { + function tiff2pdf($tiff_file_name){ + //convert the tif to a pdf + //Ubuntu: apt-get install libtiff-tools + + global $IS_WINDOWS; + + if(!file_exists($tiff_file_name)){ + echo "tiff file does not exists"; + return false; // "tiff file does not exists"; + } + + $GS = $IS_WINDOWS ? 'gswin32c' : 'gs'; + $tiff_file = pathinfo($tiff_file_name); + $dir_fax = $tiff_file['dirname']; + $fax_file_name = $tiff_file['filename']; + $pdf_file_name = path_join( $dir_fax, $fax_file_name . '.pdf' ); + + if(file_exists($pdf_file_name)) + return $pdf_file_name; + + $dir_fax_temp = $_SESSION['server']['temp']['dir']; + if(!$dir_fax_temp){ + $dir_fax_temp = path_join(dirname($dir_fax), 'temp'); + } + + if(!file_exists($dir_fax_temp)){ + echo"can not create temporary directory"; + return false; // + } + + $cmd = "tiffinfo " . correct_path($tiff_file_name) . ' | grep "Resolution:"'; + $ok = false; + $resp = exec_in_dir($dir_fax, $cmd, $ok); + if(!$ok){ + echo"can not find fax resoulution"; + return false; // "can not find fax resoulution" + } + + $ppi_w = 0; + $ppi_h = 0; + $tmp = array(); + if(preg_match('/Resolution.*?(\d+).*?(\d+)/', $resp, $tmp)){ + $ppi_w = $tmp[1]; + $ppi_h = $tmp[2]; + } + + $cmd = "tiffinfo " . $tiff_file_name . ' | grep "Image Width:"'; + $resp = exec_in_dir($dir_fax, $cmd, $ok); + if(!$ok){ + echo"can not find fax size"; + return false; // "can not find fax size" + } + + $pix_w = 0; + $pix_h = 0; + $tmp = array(); + if(preg_match('/Width.*?(\d+).*?Length.*?(\d+)/', $resp, $tmp)){ + $pix_w = $tmp[1]; + $pix_h = $tmp[2]; + } + + $page_width = $pix_w / $ppi_w; + $page_height = $pix_h / $ppi_h; + $page_size = 'a4'; + + if (($page_width > 8.4) && ($page_height > 13)) { + $page_width = 8.5; + $page_height = 14; + $page_size = 'legal'; + } + elseif (($page_width > 8.4) && ($page_height < 12)) { + $page_width = 8.5; + $page_height = 11; + $page_size = 'letter'; + } + elseif (($page_width < 8.4) && ($page_height > 11)) { + $page_width = 8.3; + $page_height = 11.7; + $page_size = 'a4'; + } + $page_width = sprintf('%.4f', $page_width); + $page_height = sprintf('%.4f', $page_height); + + $cmd = join(array('tiff2pdf', + '-i -u i', + '-p', $page_size, + '-w', $page_width, + '-l', $page_height, + '-f', + '-o', correct_path(path_join($dir_fax_temp, $fax_file_name . '.pdf')), + correct_path($tiff_file_name), + ), ' '); + + $resp = exec_in_dir($dir_fax, $cmd, $ok); + + if(!file_exists(path_join($dir_fax_temp, $fax_file_name . '.pdf'))){ + echo "can not create temporary pdf: $resp"; + return false; + } + + $cmd = join(array($GS, + '-q -sDEVICE=tiffg3', + '-r' . $ppi_w . 'x' . $ppi_h, + '-g' . $pix_w . 'x' . $pix_h, + '-dNOPAUSE', + '-sOutputFile=' . $fax_file_name . '_temp.tif', + '--', + $fax_file_name . '.pdf', + '-c quit', + ), ' '); + + $resp = exec_in_dir($dir_fax_temp, $cmd, $ok); + + unlink(path_join($dir_fax_temp, $fax_file_name . '.pdf')); + + if(!file_exists(path_join($dir_fax_temp, $fax_file_name . '_temp.tif'))){ + echo "can not temporary tiff: $resp"; + return false; + } + + $cmd = join(array('tiff2pdf', + '-i -u i', + '-p', $page_size, + '-w', $page_width, + '-l', $page_height, + '-f', + '-o', correct_path($pdf_file_name), + correct_path(path_join($dir_fax_temp, $fax_file_name . '_temp.tif')), + ), ' '); + + $resp = exec_in_dir($dir_fax, $cmd, $ok); + + unlink(path_join($dir_fax_temp, $fax_file_name . '_temp.tif')); + + if(!file_exists($pdf_file_name)){ + echo "can not create pdf: $resp"; + return false; + } + + return $pdf_file_name; + } +} + +if(!function_exists('fax_enqueue')) { + function fax_enqueue($fax_uuid, $fax_file, $wav_file, $fax_uri, $fax_dtmf, $dial_string){ + global $db, $db_type; + + $task_uuid = uuid(); + $dial_string .= "task_uuid='" . $task_uuid . "',"; + $description = ''; //! @todo add description + if ($db_type == "pgsql") { + $date_utc_now_sql = "NOW() at time zone 'utc'"; + } + if ($db_type == "mysql") { + $date_utc_now_sql = "UTC_TIMESTAMP()"; + } + if ($db_type == "sqlite") { + $date_utc_now_sql = "datetime('now')"; + } + $sql = <<prepare($sql); + $i = 0; + $stmt->bindValue(++$i, $task_uuid); + $stmt->bindValue(++$i, $fax_uuid); + $stmt->bindValue(++$i, $fax_file); + $stmt->bindValue(++$i, $wav_file); + $stmt->bindValue(++$i, $fax_uri); + $stmt->bindValue(++$i, $dial_string); + $stmt->bindValue(++$i, $fax_dtmf); + $stmt->bindValue(++$i, $description); + if ($stmt->execute()) { + $response = 'Enqueued'; + } + else{ + //! @todo log error + $response = 'Fail enqueue'; + var_dump($db->errorInfo()); + } + unset($stmt); + return $response; + } +} + +if(!function_exists('fax_split_dtmf')) { + function fax_split_dtmf(&$fax_number, &$fax_dtmf){ + $tmp = array(); + $fax_dtmf = ''; + if(preg_match('/^\s*(.*?)\s*\((.*)\)\s*$/', $fax_number, $tmp)){ + $fax_number = $tmp[1]; + $fax_dtmf = $tmp[2]; + } + } +} + //includes if (!defined('STDIN')) { include "root.php"; } require_once "resources/require.php"; @@ -111,19 +371,12 @@ if (defined('STDIN')) { } $mailto_address = $fax_email; - echo "mailto_adress is ".$mailto_address."\n"; - echo "fax_email is ".$fax_email."\n"; //get the fax file name (only) if a full path - $array = explode("/", $fax_file); - $fax_file_only = $array[count($array)-1]; - $fax_file_name = pathinfo($fax_file_only, PATHINFO_FILENAME); - unset($array); - -//used for debug - echo "fax_email $fax_email\n"; - echo "fax_extension $fax_extension\n"; - echo "fax_name $fax_file_only\n"; + $fax_path = pathinfo($fax_file); + $fax_file_only = $fax_path['basename']; + $fax_file_name = $fax_path['filename']; + $dir_fax = $fax_path['dirname']; //get the domain_uuid from the database $sql = "select * from v_domains "; @@ -153,6 +406,7 @@ if (defined('STDIN')) { foreach ($result as &$row) { //set database fields as variables //$fax_email = $row["fax_email"]; + $fax_uuid = $row["fax_uuid"]; $fax_accountcode = $row["fax_accountcode"]; $fax_pin_number = $row["fax_pin_number"]; $fax_caller_id_name = $row["fax_caller_id_name"]; @@ -164,129 +418,128 @@ if (defined('STDIN')) { unset ($prep_statement); //set the fax directory - $dir_fax = $_SESSION['switch']['storage']['dir'].'/fax/'.$domain_name.'/'.$fax_extension.'/inbox'; - echo "dir_fax is $dir_fax\n"; - if (!file_exists($dir_fax)) { - $dir_fax = $_SESSION['switch']['storage']['dir'].'/fax/'.$fax_extension.'/inbox'; - } - -//convert the tif to a pdf - //Ubuntu: apt-get install libtiff-tools - $fax_file_warning = ""; - if (file_exists($dir_fax.'/'.$fax_file_name.".tif")) { - if (!file_exists($dir_fax.'/'.$fax_file_name.".pdf")) { - //define temp directory - $dir_fax_temp = str_replace('/inbox', '/temp', $dir_fax); - if (!is_dir($dir_fax_temp)) { - mkdir($dir_fax_temp,0774,true); - chmod($dir_fax_temp,0774); - } - //enter fax directory - chdir($dir_fax); - //get fax resolution (ppi, W & H) - $resp = exec("tiffinfo ".$fax_file_name.".tif | grep 'Resolution:'"); - $resp_array = explode(' ', trim($resp)); - $ppi_w = (int) $resp_array[1]; - $ppi_h = (int) $resp_array[2]; - unset($resp_array); - $gs_r = $ppi_w.'x'.$ppi_h; //used by ghostscript - //get page dimensions/size (pixels/inches, W & H) - $resp = exec("tiffinfo ".$fax_file_name.".tif | grep 'Image Width:'"); - $resp_array = explode(' ', trim($resp)); - $pix_w = $resp_array[2]; - $pix_h = $resp_array[5]; - unset($resp_array); - $gs_g = $pix_w.'x'.$pix_h; //used by ghostscript - $page_width = $pix_w / $ppi_w; - $page_height = $pix_h / $ppi_h; - if ($page_width > 8.4 && $page_height > 13) { - $page_width = 8.5; - $page_height = 14; - $page_size = 'legal'; - } - else if ($page_width > 8.4 && $page_height < 12) { - $page_width = 8.5; - $page_height = 11; - $page_size = 'letter'; - } - else if ($page_width < 8.4 && $page_height > 11) { - $page_width = 8.3; - $page_height = 11.7; - $page_size = 'a4'; - } - //generate pdf (a work around, as tiff2pdf improperly inverts the colors) - $cmd_tif2pdf = "tiff2pdf -i -u i -p ".$page_size." -w ".$page_width." -l ".$page_height." -f -o ".$dir_fax_temp.'/'.$fax_file_name.".pdf ".$dir_fax.'/'.$fax_file_name.".tif"; - exec($cmd_tif2pdf); - chdir($dir_fax_temp); - $cmd_pdf2tif = "gs -q -sDEVICE=tiffg3 -r".$gs_r." -g".$gs_g." -dNOPAUSE -sOutputFile=".$fax_file_name."_temp.tif -- ".$fax_file_name.".pdf -c quit"; - exec($cmd_pdf2tif); //convert pdf to tif - @unlink($dir_fax_temp.'/'.$fax_file_name.".pdf"); - $cmd_tif2pdf = "tiff2pdf -i -u i -p ".$page_size." -w ".$page_width." -l ".$page_height." -f -o ".$dir_fax.'/'.$fax_file_name.".pdf ".$dir_fax_temp.'/'.$fax_file_name."_temp.tif"; - exec($cmd_tif2pdf); - @unlink($dir_fax_temp.'/'.$fax_file_name."_temp.tif"); + if (!file_exists($dir_fax) || !file_exists(path_join($dir_fax, $fax_file_only))) { + $dir_fax = $_SESSION['switch']['storage']['dir'].'/fax/'.$domain_name.'/'.$fax_extension.'/inbox'; + if (!file_exists($dir_fax) || !file_exists(path_join($dir_fax, $fax_file_only))) { + $dir_fax = $_SESSION['switch']['storage']['dir'].'/fax/'.$fax_extension.'/inbox'; } } - else { - $fax_file_warning = " Fax image not available on server."; - echo $fax_file_warning."
"; + + $fax_file = path_join($dir_fax, $fax_file_only); + +//used for debug + echo "mailto_adress is $mailto_address\n"; + echo "fax_email is $fax_email\n"; + echo "fax_extension is $fax_extension\n"; + echo "fax_name is $fax_file_only\n"; + echo "dir_fax is $dir_fax\n"; + echo "full_path is $fax_file\n"; + + $pdf_file = tiff2pdf($fax_file); + if(!$pdf_file){ + $fax_file_warning = ' Fax image not available on server.'; } + else{ + $fax_file_warning = ''; + } + +//used for debug + echo "pdf file is $pdf_file\n"; //forward the fax - if (strpos($fax_file_name,'#') !== false) { - $tmp = explode("#",$fax_file_name); - $fax_forward_number = $tmp[0]; - } + if(file_exists($fax_file)) { + if (strpos($fax_file_name,'#') !== false) { + $tmp = explode("#",$fax_file_name); + $fax_forward_number = $tmp[0]; + } - echo "fax_forward_number is $fax_forward_number\n"; - if (strlen($fax_forward_number) > 0) { - if (file_exists($dir_fax."/".$fax_file_name.".tif")) { - //get the event socket information - $sql = "select * from v_settings "; - $prep_statement = $db->prepare(check_sql($sql)); - $prep_statement->execute(); - $result = $prep_statement->fetchAll(PDO::FETCH_ASSOC); - foreach ($result as &$row) { - $event_socket_ip_address = $row["event_socket_ip_address"]; - $event_socket_port = $row["event_socket_port"]; - $event_socket_password = $row["event_socket_password"]; - break; - } - //create the event socket connection - $fp = event_socket_create($event_socket_ip_address, $event_socket_port, $event_socket_password); - //send the command with event socket - if ($fp) { - //prepare the fax originate command - $route_array = outbound_route_to_bridge($_SESSION['domain_uuid'], $fax_forward_number); - $fax_file = $dir_fax."/".$fax_file_name.".tif"; - if (count($route_array) == 0) { - //send the internal call to the registered extension - $fax_uri = "user/".$fax_forward_number."@".$domain_name; - $t38 = ""; - } - else { - //send the external call - $fax_uri = $route_array[0]; - $t38 = "fax_enable_t38=true,fax_enable_t38_request=true"; - } - $cmd = "api originate {absolute_codec_string='PCMU,PCMA',accountcode='".$fax_accountcode."',sip_h_X-accountcode='".$fax_accountcode."',domain_uuid=".$_SESSION["domain_uuid"].",domain_name=".$_SESSION["domain_name"].",mailto_address='".$mailto_address."',mailfrom_address='".$mailfrom_address."',origination_caller_id_name='".$fax_caller_id_name."',origination_caller_id_number=".$fax_caller_id_number.",fax_uri=".$fax_uri.",fax_file='".$fax_file."',fax_retry_attempts=1,fax_retry_limit=20,fax_retry_sleep=180,fax_verbose=true,fax_use_ecm=off,".$t38.",api_hangup_hook='lua fax_retry.lua'}".$fax_uri." &txfax('".$fax_file."')"; - //send info to the log - echo "fax forward\n"; - echo $cmd."\n"; - //send the command to event socket - $response = event_socket_request($fp, $cmd); - $response = str_replace("\n", "", $response); - //send info to the log - echo "response: ".$response."\n"; - //get the uuid - $uuid = str_replace("+OK ", "", $response); - //close event socket - fclose($fp); - } + echo "fax_forward_number is $fax_forward_number\n"; + if (strlen($fax_forward_number) > 0) { + fax_split_dtmf($fax_forward_number, $fax_dtmf); + + $fax_send_mode = $_SESSION['fax']['send_mode']['text']; + if(strlen($fax_send_mode) == 0){ + $fax_send_mode = 'direct'; + } + + $route_array = outbound_route_to_bridge($_SESSION['domain_uuid'], $fax_forward_number); + if (count($route_array) == 0) { + //send the internal call to the registered extension + $fax_uri = "user/".$fax_forward_number."@".$domain_name; + $t38 = ""; + } + else { + //send the external call + $fax_uri = $route_array[0]; + $t38 = "fax_enable_t38=true,fax_enable_t38_request=true"; + } + + $common_dial_string = "absolute_codec_string='PCMU,PCMA',"; + $common_dial_string .= "accountcode='" . $fax_accountcode . "',"; + $common_dial_string .= "sip_h_X-accountcode='" . $fax_accountcode . "',"; + $common_dial_string .= "domain_uuid=" . $_SESSION["domain_uuid"] . ","; + $common_dial_string .= "domain_name=" . $_SESSION["domain_name"] . ","; + $common_dial_string .= "mailto_address='" . $mailto_address . "',"; + $common_dial_string .= "mailfrom_address='" . $mailfrom_address . "',"; + $common_dial_string .= "origination_caller_id_name='" . $fax_caller_id_name . "',"; + $common_dial_string .= "origination_caller_id_number='" . $fax_caller_id_number . "',"; + $common_dial_string .= "fax_ident='" . $fax_caller_id_number . "',"; + $common_dial_string .= "fax_header='" . $fax_caller_id_name . "',"; + $common_dial_string .= "fax_file='" . $fax_file . "',"; + + if ($fax_send_mode != 'queue') { + $dial_string .= $t38; + $dial_string .= "fax_uri=" . $fax_uri . ","; + $dial_string .= "fax_retry_attempts=1" . ","; + $dial_string .= "fax_retry_limit=20" . ","; + $dial_string .= "fax_retry_sleep=180" . ","; + $dial_string .= "fax_verbose=true" . ","; + $dial_string .= "fax_use_ecm=off" . ","; + $dial_string .= "api_hangup_hook='lua fax_retry.lua'"; + $dial_string = "{" . $dial_string . "}" . $fax_uri." &txfax('".$fax_file."')"; + + //get the event socket information + $sql = "select * from v_settings "; + $prep_statement = $db->prepare(check_sql($sql)); + $prep_statement->execute(); + $result = $prep_statement->fetchAll(PDO::FETCH_ASSOC); + foreach ($result as &$row) { + $event_socket_ip_address = $row["event_socket_ip_address"]; + $event_socket_port = $row["event_socket_port"]; + $event_socket_password = $row["event_socket_password"]; + break; + } + + //create the event socket connection + $fp = event_socket_create($event_socket_ip_address, $event_socket_port, $event_socket_password); + + //send the command with event socket + if ($fp) { + //prepare the fax originate command + $cmd = "api originate " . $dial_string; + //send info to the log + echo "fax forward\n"; + echo $cmd."\n"; + //send the command to event socket + $response = event_socket_request($fp, $cmd); + $response = str_replace("\n", "", $response); + //send info to the log + echo "response: ".$response."\n"; + //get the uuid + $uuid = str_replace("+OK ", "", $response); + //close event socket + fclose($fp); + } + } + else{ + $wav_file = ''; + $response = fax_enqueue($fax_uuid, $fax_file, $wav_file, $fax_uri, $fax_dtmf, $dial_string); + } } } //send the email - if (strlen($fax_email) > 0 && file_exists($dir_fax."/".$fax_file_name.".tif")) { + if (strlen($fax_email) > 0 && file_exists($fax_file)) { //prepare the message $tmp_subject = (($fax_email_inbound_subject_tag != '') ? "[".$fax_email_inbound_subject_tag."]" : "Fax Received").": ".$fax_file_name; @@ -340,11 +593,11 @@ if (defined('STDIN')) { //add the attachments if (strlen($fax_file_name) > 0) { - if (file_exists($dir_fax.'/'.$fax_file_name.".pdf")) { - $mail->AddAttachment($dir_fax.'/'.$fax_file_name.'.pdf'); // pdf attachment + if ($pdf_file && file_exists($pdf_file)) { + $mail->AddAttachment($pdf_file); // pdf attachment } else { - $mail->AddAttachment($dir_fax.'/'.$fax_file_name.'.tif'); // tif attachment + $mail->AddAttachment($fax_file); // tif attachment } //$filename='fax.tif'; $encoding = "base64"; $type = "image/tif"; //$mail->AddStringAttachment(base64_decode($strfax),$filename,$encoding,$type); @@ -373,7 +626,7 @@ if (defined('STDIN')) { // failed_fax_emails.sh - this is created when we have a email we need to re-send. At the time it is created, an at job is created to execute it in 3 minutes time, // this allows us to try sending the email again at that time. If the file exists but there is no at job this is because there are no longer any emails queued // as we have successfully sent them all. - if (strlen($fax_email) > 0 && file_exists($dir_fax."/".$fax_file_name.".tif")) { + if (strlen($fax_email) > 0 && file_exists($fax_file)) { if (stristr(PHP_OS, 'WIN')) { //not compatible with windows } @@ -387,7 +640,7 @@ if (defined('STDIN')) { } else { // create an instruction log to email messages once the connection to the mail server has been restored $fp = fopen($fax_to_email_queue_dir."/failed_fax_emails.log", "a"); - fwrite($fp, PHP_BINDIR."/php ".$_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/secure/fax_to_email.php email='".$fax_email."' extension=".$fax_extension." name='".$dir_fax.'/'.$fax_file_only."' messages='".$fax_messages."' domain=".$domain_name." caller_id_name='".$caller_id_name."' caller_id_number=".$caller_id_number." retry=true\n"); + fwrite($fp, PHP_BINDIR."/php ".$_SERVER["DOCUMENT_ROOT"].PROJECT_PATH."/secure/fax_to_email.php email='".$fax_email."' extension=".$fax_extension." name='".$fax_file."' messages='".$fax_messages."' domain=".$domain_name." caller_id_name='".$caller_id_name."' caller_id_number=".$caller_id_number." retry=true\n"); fclose($fp); // create a script to do the delayed mailing $fp = fopen($_SESSION['server']['temp']['dir']."/failed_fax_emails.sh", "w"); @@ -413,4 +666,4 @@ if (defined('STDIN')) { fwrite($fp, $content); fclose($fp); -?> +?> \ No newline at end of file