From ea1bd1afd46986ce22f4a5a7db30878bce8ea400 Mon Sep 17 00:00:00 2001 From: sunsetsystems Date: Sat, 23 Sep 2006 12:46:31 +0000 Subject: [PATCH] added general-purpose fax support --- INSTALL | 9 + custom/faxcover.txt | 13 + interface/fax/fax_dispatch.php | 531 ++++++++++++++++++ interface/fax/fax_view.php | 31 + interface/fax/faxq.php | 100 ++++ interface/globals.php | 6 + interface/main/main_navigation.php | 6 + .../patient_file/summary/pnotes_full.php | 15 +- library/pnotes.inc | 11 + 9 files changed, 709 insertions(+), 13 deletions(-) create mode 100644 custom/faxcover.txt create mode 100644 interface/fax/fax_dispatch.php create mode 100644 interface/fax/fax_view.php create mode 100644 interface/fax/faxq.php diff --git a/INSTALL b/INSTALL index 46af80da347..fccd447d5df 100644 --- a/INSTALL +++ b/INSTALL @@ -145,6 +145,15 @@ Everything should work out of the installation without touching those, but if you want fax, sql-ledger, and/or Freeb integration you will need to adjust some parameters in that file. +General-purpose fax support requires customization of interface/globals.php +and custom/faxcover.txt; it also requires the following utilities: + +* faxstat and sendfax from the HylaFAX client package +* mogrify from the ImageMagick package +* tiff2pdf, tiffcp and tiffsplit from the libtiff-tools package +* enscript + + IV. Setting Up Access Control As of this writing the option of adding phpGACL to your OpenEMR installation is diff --git a/custom/faxcover.txt b/custom/faxcover.txt new file mode 100644 index 00000000000..409d0797235 --- /dev/null +++ b/custom/faxcover.txt @@ -0,0 +1,13 @@ + FACSIMILE TRANSMISSION + {CURRENT_DATE} + + +From: {SENDER_NAME} + Your Company Name Phone: 222-333-4444 + Your Company Address Fax: 555-666-7777 + Your City, State Zip + +To: {RECIPIENT_NAME} +Fax: {RECIPIENT_FAX} + +{MESSAGE} diff --git a/interface/fax/fax_dispatch.php b/interface/fax/fax_dispatch.php new file mode 100644 index 00000000000..8415f4bc194 --- /dev/null +++ b/interface/fax/fax_dispatch.php @@ -0,0 +1,531 @@ + + // + // This program is free software; you can redistribute it and/or + // modify it under the terms of the GNU General Public License + // as published by the Free Software Foundation; either version 2 + // of the License, or (at your option) any later version. + + include_once("../globals.php"); + include_once("$srcdir/patient.inc"); + include_once("$srcdir/pnotes.inc"); + + $filename = escapeshellcmd($_GET['file']); + $filepath = $GLOBALS['hylafax_basedir'] . '/recvq/' . $filename; + $filebase = basename("/$filename", '.tif'); + $faxcache = "$webserver_root/faxcache/$filebase"; + + $info_msg = ""; + + // This function builds an array of document categories recursively. + // Kittens are the children of cats, you know. :-) + // + function getKittens($catid, $catstring, &$categories) { + $cres = sqlStatement("SELECT id, name FROM categories " . + "WHERE parent = $catid ORDER BY name"); + $childcount = 0; + while ($crow = sqlFetchArray($cres)) { + ++$childcount; + getKittens($crow['id'], ($catstring ? "$catstring / " : "") . + ($catid ? $crow['name'] : ''), $categories); + } + // If no kitties, then this is a leaf node and should be listed. + if (!$childcount) $categories[$catid] = $catstring; + } + + // This merges the tiff files for the selected pages into one tiff file. + // + function mergeTiffs() { + global $faxcache; + $msg = ''; + $inames = ''; + $tmp1 = array(); + $tmp2 = 0; + foreach ($_POST['form_images'] as $inbase) { + $inames .= ' ' . escapeshellarg("$inbase.tif"); + } + if (!$inames) die("Internal error - no pages were selected!"); + $tmp0 = exec("cd '$faxcache'; tiffcp $inames temp.tif", $tmp1, $tmp2); + if ($tmp2) { + $msg .= "tiffcp returned $tmp2: $tmp0 "; + } + return $msg; + } + + // If we are submitting... + // + if ($_POST['form_save']) { + $action_taken = false; + $tmp1 = array(); + $tmp2 = 0; + + if ($_POST['form_cb_copy']) { + $patient_id = (int) $_POST['form_pid']; + if (!$patient_id) die('Internal error - patient ID was not provided!'); + // Compute the name of the target directory and make sure it exists. + $docdir = "$webserver_root/documents/$patient_id"; + exec("mkdir -p '$docdir'"); + // Compute a target filename that does not yet exist. + $ffmod = ''; + $ffsuff = '.pdf'; + // If the target filename exists, modify it until it doesn't. + $count = 0; + while (is_file("$docdir/$filebase$ffmod$ffsuff")) { + ++$count; + $ffmod = "_$count"; + } + $target = "$docdir/$filebase$ffmod$ffsuff"; + + // Create the target PDF. + $info_msg .= mergeTiffs(); + $tmp0 = exec("tiff2pdf -p letter -o '$target' '$faxcache/temp.tif'", $tmp1, $tmp2); + if ($tmp2) { + $info_msg .= "tiff2pdf returned $tmp2: $tmp0 "; + } + else { + $newid = generate_id(); + $fsize = filesize($target); + $catid = (int) $_POST['form_category']; + // Update the database. + $query = "INSERT INTO documents ( " . + "id, type, size, date, url, mimetype, foreign_id" . + " ) VALUES ( " . + "'$newid', 'file_url', '$fsize', NOW(), 'file://$target', " . + "'application/pdf', $patient_id " . + ")"; + sqlStatement($query); + $query = "INSERT INTO categories_to_documents ( " . + "category_id, document_id" . + " ) VALUES ( " . + "'$catid', '$newid' " . + ")"; + sqlStatement($query); + + // If we are posting a note... + if ($_POST['form_cb_note']) { + // Build note text in a way that identifies the new document. + // See pnotes_full.php which uses this to auto-display the document. + $note = "$filebase$ffmod$ffsuff"; + for ($tmp = $catid; $tmp;) { + $catrow = sqlQuery("SELECT name, parent FROM categories WHERE id = '$tmp'"); + $note = $catrow['name'] . "/$note"; + $tmp = $catrow['parent']; + } + $note = "New scanned document $newid: $note"; + $form_note_message = trim($_POST['form_note_message']); + if (get_magic_quotes_gpc()) $form_note_message = stripslashes($form_note_message); + if ($form_note_message) $note .= "\n" . $form_note_message; + // addPnote() will do its own addslashes(). + addPnote($_POST['form_pid'], $note, $userauthorized, '1', + $_POST['form_note_type'], $_POST['form_note_to']); + } + + $action_taken = true; + } + } + + if ($_POST['form_cb_forward']) { + $form_from = trim($_POST['form_from']); + $form_to = trim($_POST['form_to']); + $form_fax = trim($_POST['form_fax']); + $form_message = trim($_POST['form_message']); + $form_finemode = $_POST['form_finemode'] ? ' -m' : ''; + + // Generate a cover page using enscript. This can be a cool thing + // to do, as enscript is very powerful. + // + $tmp1 = array(); + $tmp2 = 0; + $tmpfn1 = tempnam("/tmp", "fax1"); + $tmpfn2 = tempnam("/tmp", "fax2"); + $tmph = fopen($tmpfn1, "w"); + $cpstring = ''; + $fh = fopen("$webserver_root/custom/faxcover.txt", 'r'); + while (!feof($fh)) $cpstring .= fread($fh, 8192); + fclose($fh); + $cpstring = str_replace('{CURRENT_DATE}' , date('F j, Y'), $cpstring); + $cpstring = str_replace('{SENDER_NAME}' , $form_from , $cpstring); + $cpstring = str_replace('{RECIPIENT_NAME}', $form_to , $cpstring); + $cpstring = str_replace('{RECIPIENT_FAX}' , $form_fax , $cpstring); + $cpstring = str_replace('{MESSAGE}' , $form_message , $cpstring); + fwrite($tmph, $cpstring); + fclose($tmph); + $tmp0 = exec($GLOBALS['hylafax_enscript'] . " -o $tmpfn2 $tmpfn1", + $tmp1, $tmp2); + if ($tmp2) { + $info_msg .= "enscript returned $tmp2: $tmp0 "; + } + unlink($tmpfn1); + + // Send the fax as the cover page followed by the selected pages. + $info_msg .= mergeTiffs(); + $tmp0 = exec("sendfax -n$form_finemode -d " . + escapeshellarg($form_fax) . " $tmpfn2 '$faxcache/temp.tif'", + $tmp1, $tmp2); + if ($tmp2) { + $info_msg .= "sendfax returned $tmp2: $tmp0 "; + } + unlink($tmpfn2); + + $action_taken = true; + } + + if ($_POST['form_cb_delete'] && !$info_msg) { + // Delete the tiff file. + unlink($filepath); + + // Erase its cache. + if (is_dir($faxcache)) { + $dh = opendir($faxcache); + while (($tmp = readdir($dh)) !== false) { + if (is_file("$faxcache/$tmp")) unlink("$faxcache/$tmp"); + } + closedir($dh); + rmdir($faxcache); + } + + $action_taken = true; + } + + if (!$action_taken && !$info_msg) + $info_msg = 'You did not choose any actions.'; + + // Close this window and refresh the fax list. + echo "\n\n\n\n\n"; + exit(); + } + + // If we get this far then we are displaying the form. + + // If the image cache does not yet exist for this fax, build it. + if (! is_dir($faxcache)) { + $tmp0 = exec("mkdir -p '$faxcache'", $tmp1, $tmp2); + if ($tmp2) die("mkdir returned $tmp2: $tmp0"); + $tmp0 = exec("cd '$faxcache'; tiffsplit '$filepath'", $tmp1, $tmp2); + if ($tmp2) die("tiffsplit returned $tmp2: $tmp0"); + $tmp0 = exec("cd '$faxcache'; mogrify -resize 600x776 -format jpg *.tif", $tmp1, $tmp2); + if ($tmp2) die("mogrify returned $tmp2: $tmp0"); + } + + // Get the categories list. + $categories = array(); + getKittens(0, '', $categories); + + // Get the users list. + $ures = sqlStatement("SELECT username, fname, lname FROM users " . + "ORDER BY lname, fname"); +?> + + +Dispatch Received Document + + + + + + + + + + + + + onunload='imclosing()'> + +

Dispatch Received Document

+ +
+ +

+Copy Pages to Patient Chart

+ + + +

+Forward Pages via Fax

+ + + +

+Delete Fax from Queue

+ +
+

+ +    + +

+ +


Please select the desired pages to copy or forward:

+ + +\n"; + echo " \n"; + echo " \n"; + echo " \n"; + } + } + closedir($dh); +?> + +
\n"; + echo " \n"; + echo " \n"; + echo " \n"; + echo "
$page\n"; + echo "
+
+
+ + + diff --git a/interface/fax/fax_view.php b/interface/fax/fax_view.php new file mode 100644 index 00000000000..fcb0b19bdc3 --- /dev/null +++ b/interface/fax/fax_view.php @@ -0,0 +1,31 @@ + + // + // This program is free software; you can redistribute it and/or + // modify it under the terms of the GNU General Public License + // as published by the Free Software Foundation; either version 2 + // of the License, or (at your option) any later version. + + require_once("../globals.php"); + + $ffname = $GLOBALS['hylafax_basedir'] . '/recvq/' . $_GET['file']; + + if (!file_exists($ffname)) { + die(xl("Cannot access ") . $ffname); + } + + ob_start(); + + passthru("tiff2pdf $ffname"); + + header("Pragma: public"); + header("Expires: 0"); + header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); + header("Content-Type: application/pdf"); + header("Content-Length: " . ob_get_length()); + header("Content-Disposition: inline; filename=" . basename($ffname, '.tif') . '.pdf'); + + ob_end_flush(); + + exit; +?> \ No newline at end of file diff --git a/interface/fax/faxq.php b/interface/fax/faxq.php new file mode 100644 index 00000000000..fa68176019a --- /dev/null +++ b/interface/fax/faxq.php @@ -0,0 +1,100 @@ + + // + // This program is free software; you can redistribute it and/or + // modify it under the terms of the GNU General Public License + // as published by the Free Software Foundation; either version 2 + // of the License, or (at your option) any later version. + + require_once("../globals.php"); + require_once("$srcdir/acl.inc"); + + // Get the recvq entries, parse and sort by filename. + // + $statlines = array(); + exec("faxstat -r -l -h " . $GLOBALS['hylafax_server'], $statlines); + $mlines = array(); + foreach ($statlines as $line) { + // This gets pagecount, sender, time, filename. + if (preg_match('/^-\S+\s+(\d+)\s+\S+\s+(.+)\s+(\S+)\s+(\S+)\s*$/', $line, $matches)) { + $mlines[$matches[4]] = $matches; + } + } + ksort($mlines); + + // echo "\n"; // debugging + +?> + + + + + +<? xl('Received Faxes','e'); ?> + + + + + + + + + +> +
+ + + + + + + + +\n"; + echo " \n"; + // echo "$ffname\n"; + echo " \n"; + echo " \n"; + echo " \n"; + echo " \n"; + echo " \n"; + } +?> +
"; + echo "$ffbase"; + echo "Dispatch" . htmlentities($matches[3]) . "" . htmlentities($matches[2]) . "" . htmlentities($matches[1]) . "
+ +
+ + diff --git a/interface/globals.php b/interface/globals.php index 74804f7e5dd..3353a9c2edc 100644 --- a/interface/globals.php +++ b/interface/globals.php @@ -163,6 +163,12 @@ // You may put text here as the default complaint in the New Patient form: $GLOBALS['default_chief_complaint'] = ''; +// If you want Hylafax support then uncomment and customize the following +// statements, and also customize custom/faxcover.txt: +// $GLOBALS['hylafax_server'] = 'localhost'; +// $GLOBALS['hylafax_basedir'] = '/var/spool/fax'; +// $GLOBALS['hylafax_enscript'] = 'enscript -M Letter -f Courier@12 -B --margins=36:36:36:36'; + // Customize these if you are using SQL-Ledger with OpenEMR. $sl_cash_acc = '1060'; // sql-ledger account number for checking account $sl_ar_acc = '1200'; // sql-ledger account number for accounts receivable diff --git a/interface/main/main_navigation.php b/interface/main/main_navigation.php index ef714bfd2a5..57477f5f63c 100644 --- a/interface/main/main_navigation.php +++ b/interface/main/main_navigation.php @@ -61,6 +61,12 @@    + + +   + + +    diff --git a/interface/patient_file/summary/pnotes_full.php b/interface/patient_file/summary/pnotes_full.php index cf5e637fafb..3fe458c509b 100644 --- a/interface/patient_file/summary/pnotes_full.php +++ b/interface/patient_file/summary/pnotes_full.php @@ -15,17 +15,6 @@ //the number of records to display per screen $N = 25; -$note_types = array( - 'Unassigned', - 'Chart Note', - 'Insurance', - 'New Document', - 'Pharmacy', - 'Prior Auth', - 'Referral', - 'Test Scheduling', - 'Other'); - $mode = $_REQUEST['mode']; $offset = $_REQUEST['offset']; $active = $_REQUEST['active']; @@ -116,7 +105,7 @@ :