<?
// Author:   Roger Banks - ke5aqd@ke5aad.com
// Date:     05 April 2005
// File:     log.php
// Language: PHP
//
// Usage: "http://.../log.php[?source=1]
//
// Description:
// This script parses a exported XML file from jLog
// and outputs a formatted HTML Ham radio contact log.
// The format of the XML input file is:
// <ADIF>
//    <header>
//       <version></version>
//       <description></description>
//       <exported-by>
//          <program></program>
//          <version></version>
//          <contacts></contacts>
//       </exported-by>
//    </header>
//      <qso>
//        <qso-date></qso-date>
//      <time-on></time-on>
//      <call></call>
//        <band></band>
//      <mode></mode>
//      <tx-pwr></tx-pwr>
//        <rst-sent></rst-sent>
//        <rst-rcvd></rst-rcvd>
//        <time-off></time-off>
//        <name></name>
//        <qth></qth>
//        <qsl-sdate></qsl-sdate>
//        <qsl-rcvd></qsl-rcvd>
//        <sat-name></sat-name>
//        <comment></comment>
//        <dcxx></dcxx>
//        <ituz></ituz>
//        <cqz></cqz>
//        <pfx></pfx>
//        <cont></cont>
//        <state></state>
//        <cnty></cnty>
//        <gridsquare></gridsquare>
//      </qso>
// </ADIF>
//
// Change Log:
// 05 Apr 2005 Started Project
// 08 Apr 2005 Gutted some more leftovers. Importing just the call now.
//             Added support for alternating row colors.
// 11 Apr 2005 Added unique contacts count, fixed bug causing blank grid field
//             to contain data from previous entry.
// 12 Apr 2005 Added distance column.
// 13 Apr 2005 Added source display. Added DXCC and State counts. reformated
//             name and QTH fields.
// 16 Apr 2005 Added prefix count. Reformatted totals section.
// 19 Apr 2005 added global decl to 'end_element' so that '$qsl_rcvd' is output
// 28 Apr 2005 Added QSLs Sent and QSLs Rcvd outputs along with % returned.
//             Made callsign field into link to QRZ page.
// 02 May 2005 Added gridsquare count.
// 14 May 2005 Fixed Table header order.
// 08 Aug 2005 Added count of satellite contacts.
// 03 Oct 2005 Added PSK31 count.
// 19 Oct 2005 Added RTTY count.
//
// Todo:
// 11 Apr 2005 Better format for date and time.
// 16 Apr 2005 Count unique zones.
// 02 May 2005 Need to create script that takes an array and a string and
//             generates a sorted table listing the array with the title of
//             string. Generic lister for states, grids, prefixes, etc.

$source   'log.php';  // name of this source file
$filename 'log.xml';  // input file

if ($_REQUEST["SOURCE"] != "" || $_REQUEST["source"] != "") {
    echo 
"<HTML><HEAD><TITLE>log.php source</TITLE></HEAD><BODY><FONT SIZE=1>";
    
show_source($source);
    echo 
"</FONT></BODY></HTML>";
    exit;
}


?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=x-mac-roman">
    <title>KE5AQD Logbook</title>
    <meta name="generator" content="BBEdit 6.5.3">
    <link rel="stylesheet" type="text/css" href="css/geo.css" />
</head>
<body>
<center><H1>KE5AQD Logbook</H1></center>
<P>

<?
require("mh_functions.php");   // gridsquare routines from
                               // http://www.viestikallio.fi/tools/maidenheadfuncs.php?source=1

if (file_exists($filename)) {
    echo 
"This log is current as of: ";
    echo 
date ("F d Y H:i:s."filemtime($filename));
}

echo 
"<BR><TABLE cellspacing=0 cellpadding=3>" .
     
"<TR><TH>Date</TH><TH>UTC</TH><TH>Callsign</TH><TH>Band</TH>" .
     
"<TH>Mode</TH><TH>Pwr</TH><TH>Name</TH><TH>QTH</TH>" .
     
"<TH>Grid</TH><TH>QSL<BR>Sent</TH><TH>QSL<BR>Rcvd</TH>" .
     
"<TH>Dist<BR>(mi)</TH></TR>";

// initialize global variables
$call "";            // callsign
$qso_date "";        // qso date
$time_on "";         // qso start time
$band "";            // frequency band
$mode "";            // mode
$tx_pwr "";          // transmitter power
$name "";            // station name
$qth "";             // station location
$grid "";            // gridsquare
$qsl_sent "";        // date qsl card sent
$qsl_rcvd "";        // date qsl card received
$dxcc "";            // dxcc
$state "";           // state
$prefix "";          // prefix
$sat_name "";           // satellite name
$callsigns "";       // array of $calls
$dxccs "";           // array of dxccs
$states "";          // array of states
$prefixes "";        // array of prefixes
$gridsquares "";     // array of gridsquares
$qsls_sent 0;        // count of qsls sent
$qsls_rcvd 0;        // count of qsls rcvd
$cw_count 0;         // count of cw mode qsos
$sat_count 0;        // count of satellite contacts
$psk_count 0;        // count of PSK31 contacts
$rtty_count 0;       // count of RTTY contacts
$current_tag "";     // the name of the current XML tag being processed
$row_count 0;

///////////////////////////////////////////////////////////////////////////////
//
// Function: isEven
// Date: 13 Apr 2005
// Description:
//        Determines if input is even.
// Inputs:
//        string $num    number to test
// Outputs:
//        boolean, true if $num is even.
// Side effects:
//        none
//
///////////////////////////////////////////////////////////////////////////////
function isEven $num ) {
   return !(
$num 2);
}

///////////////////////////////////////////////////////////////////////////////
//
// Function: format_name
// Date: 13 Apr 2005
// Description:
//        Reformats person names and city, start names to correct capitalization.
// Inputs:
//        string $str    The string to reformat
// Outputs:
//        string containing reformated string
// Side effects:
//        none
//
///////////////////////////////////////////////////////////////////////////////
function format_name($str) {
    
$parts explode(','$str);
    
$name ucwords(strtolower($parts[0]));
    
$suffix trim(strtoupper($parts[1]));
    if(
$suffix == "") return $name;
    else if(
$suffix == 'JR'$suffix 'Jr';
    return 
$name ', ' $suffix;
}

///////////////////////////////////////////////////////////////////////////////
//
// Function: create_parser
// Date: 07 May 2003
// Description:
//        This function opens an XML file and creates a parser to read it
// Inputs:
//        string $filename    The name of the XML file to parse
// Outputs:
//        array return value: indicates successful file open and parser
//        creation
// Side effects:
//        none
//
///////////////////////////////////////////////////////////////////////////////
function create_parser ($filename) {
    
$fp fopen($filename'r');
    
$parser xml_parser_create();

    
xml_set_element_handler($parser'start_element''end_element');
    
xml_set_character_data_handler($parser'character_data');
    
//xml_set_processing_instruction_handler($parser, 'processing_instruction');
    //xml_set_default_handler($parser, 'default');

    
return array($parser$fp);
// create_parser

///////////////////////////////////////////////////////////////////////////////
//
// Function: parse
// Date: 07 May 2003
// Description:
//        This function parses the lines of an XML file
// Inputs:
//        $parser    Pointer to parser
//        $fp    file pointer
// Outputs:
//        array return value: indicates successful parse operation
// Side effects:
//        none
//
///////////////////////////////////////////////////////////////////////////////
function parse($parser$fp) {
    
$blocksize 1024;

    while(
$data fread($fp$blocksize)) {
        if(!
xml_parse($parser$datafeof($fp))) {
            echo 
'Parse Error: ' 
                 
xml_error_string($parser) . 
                 
" at line " 
                 
xml_get_current_line_number($parser);
            return 
FALSE;
        }
    }
    return 
TRUE;
// parse

///////////////////////////////////////////////////////////////////////////////
//
// Function: start_element
// Date: 07 May 2003
// Description:
//        This function handles start elements passed from the parser
// Inputs:
//        pointer $parser        pointer to parser
//        string  $element    the name of the element
//        array    $attributes    the elements attributes
// Outputs:
//        none
// Side effects:
//        sets values for globals
//
///////////////////////////////////////////////////////////////////////////////
function start_element($parser$element, &$attributes) {

    global 
$call;
    global 
$current_tag;
    
    
$current_tag $element;
    
//echo "Current Tag: $current_tag<BR>";
// start_element

///////////////////////////////////////////////////////////////////////////////
//
// Function: end_element
// Date: 07 May 2003
// Description:
//        This function handles end elements passed from the parser.
//        Formats $lat and $lon to display five significant digits.
// Inputs:
//        pointer $parser        pointer to parser
//        string  $element    the name of the element
// Outputs:
//        html table row containing log information
// Side effects:
//        sets value for globals
//
///////////////////////////////////////////////////////////////////////////////
function end_element($parser$element) {

    global 
$qso_date;
    global 
$time_on;
    global 
$call;
    global 
$band;
    global 
$mode;
    global 
$tx_pwr;
    global 
$name;
    global 
$qth;
    global 
$grid;
    global 
$qsl_sent;
    global 
$qsl_rcvd;
    global 
$dxcc;
    global 
$state;
    global 
$prefix;
    global 
$current_tag;
    global 
$row_count;
    global 
$callsigns;
    global 
$dxccs;
    global 
$states;
    global 
$prefixes;
    global 
$gridsquares;
    global 
$qsls_sent;       // count of qsls sent
    
global $qsls_rcvd;       // count of qsls rcvd
    
global $cw_count;        // count of cw qso
    
global $sat_count;       // count of satellite contacts
    
global $psk_count;
    global 
$rtty_count;
    global 
$sat_name;
    
    
$current_tag ""// This is important, otherwise character data will
                       // be cleared before next 'waypoint' end tag.
    
    //echo "$element<BR>";
    
if($element == "QSO") {
        if(
$grid != "") {
            
$my_qth_coords parsemaidenhead("EM10dj");
            
$station_coords parsemaidenhead($grid);
            
$dist maidenhead_km_distance($my_qth_coords$station_coords);
            
$miles $dist[s] * 0.621371192;  // convert to miles
            
$idist sprintf('%d',$miles);
        }
        
        
$row_count++;
        
$callsigns[]   = $call;
        
$states[]      = $state;
        
$prefixes[]    = $prefix;
        
$gridsquares[] = substr($grid04); // Only the first four characters
                                              // are significant
        
        
if($dxcc != 291$dxccs[]= $dxcc;     // Don't count CONUS
        
        
if($qsl_sent != "")  $qsls_sent++;
        if(
$qsl_rcvd != "")  $qsls_rcvd++;
        if(
$mode == "CW")    $cw_count++;
        if(
$sat_name != "")  $sat_count++;
        if(
$mode == "PSK31"$psk_count++;
        if(
$mode == "RTTY")  $rtty_count++;
        
        if(
isEven($row_count)) $color "#CCFFCC"// was 33FFFF
        
else $color "White";
        
        
$table_row "<TR bgcolor=$color>" .
                     
"<TD>$qso_date</TD>" .
                     
"<TD>$time_on</TD>" .
                     
"<TD><A href=http://www.qrz.com/$call>$call</A></TD>" .
                     
"<TD>$band</TD>" .
                     
"<TD>$mode</TD>" .
                     
"<TD>$tx_pwr</TD>" .
                     
"<TD>$name</TD>" .
                     
"<TD>$qth</TD>" .
                     
"<TD>$grid</TD>" .
                     
"<TD>$qsl_sent</TD>" .
                     
"<TD>$qsl_rcvd</TD>" .
                     
"<TD align=right>$idist</TD>";
        
$table_row .= "</TR>";
        echo 
$table_row;
        
//echo "end<BR>";
        
        
$grid "";
        
$qsl_sent "";
        
$qsl_rcvd "";
        
$state "";
        
$dxcc "";
        
$prefix "";
        
$sat_name "";
        
$name "";
        
$qth "";
    }
   
//echo "End Element: $element<BR>";
// end_element

///////////////////////////////////////////////////////////////////////////////
//
// Function: character_data
// Date: 07 May 2003
// Description:
//        This function handles the character data from the parser.
// Inputs:
//        pointer $parser        pointer to parser
//        string  $data       the cdata
// Outputs:
//        none
// Side effects:
//        sets values for globals
//
///////////////////////////////////////////////////////////////////////////////
function character_data($parser$data) {

    global 
$qso_date;
    global 
$time_on;
    global 
$call;
    global 
$band;
    global 
$mode;
    global 
$tx_pwr;
    global 
$name;
    global 
$qth;
    global 
$grid;
    global 
$qsl_sent;
    global 
$qsl_rcvd;
    global 
$dxcc;
    global 
$state;
    global 
$prefix;
    global 
$current_tag;
    global 
$row_count;
    global 
$sat_name;
    
    
//echo "Current Tag: $current_tag Data: -$data-<BR>"; 
    
    
if($current_tag == "CALL"$call $data;
    else if(
$current_tag == "QSO-DATE"$qso_date $data;
    else if(
$current_tag == "TIME-ON"$time_on $data;
    else if(
$current_tag == "BAND"$band $data;
    else if(
$current_tag == "MODE"$mode $data;
    else if(
$current_tag == "TX-PWR"$tx_pwr $data;
    
//else if($current_tag == "NAME") $name = ucwords(strtolower($data));
    
else if($current_tag == "NAME"$name format_name($data);
    
//else if($current_tag == "QTH") $qth = ucwords(strtolower($data));
    
else if($current_tag == "QTH"$qth format_name($data);
    else if(
$current_tag == "GRIDSQUARE"$grid $data;
    else if(
$current_tag == "QSL-SDATE"$qsl_sent $data;
    else if(
$current_tag == "QSL-RDATE"$qsl_rcvd $data;
    else if(
$current_tag == "DXCC"$dxcc $data;
    else if(
$current_tag == "STATE"$state $data;
    else if(
$current_tag == "PFX"$prefix $data;
    else if(
$current_tag == "SAT-NAME"$sat_name $data;
    
//echo "Character Data: $data<BR>";
//character_data

/*
function processing_instruction() {
}

function default() {
}
*/

// main program
if(list($parser$fp) = create_parser($filename)) {
    
parse($parser$fp);
    
fclose($fp);
    
xml_parser_free($parser);
// main

?>
</TABLE>
<HR>
<P>
<?
echo "<TABLE><TR><TD align=left>Total Contacts:</TD>";
echo 
"<TD align=right>$row_count</TD>";
echo 
"<TD>&nbsp;&nbsp;&nbsp;</TD><TD align=left>DXCC Count:</TD>";
printf('<TD align=right>%d</TD>'count(array_unique($dxccs)));
echo 
"<TD>&nbsp;&nbsp;&nbsp;</TD><TD align=left>Prefix Count:</TD>";
printf('<TD align=right>%d</TD>'count(array_unique($prefixes)));
echo 
"<TD>&nbsp;&nbsp;&nbsp;</TD><TD align=left>QSLs Sent:</TD>";
echo 
"<TD align=right>$qsls_sent</TD></TR>";
echo 
"<TR><TD>Unique Contacts:</TD>";
printf('<TD align=right>%d</TD>'count(array_unique($callsigns)));
echo 
"<TD>&nbsp;&nbsp;&nbsp;</TD><TD align=left>State Count:</TD>";
printf('<TD align=right>%d</TD>'count(array_unique($states)));
echo 
"<TD>&nbsp;&nbsp;&nbsp;</TD><TD align=left>Gridsquares:</TD>";
printf('<TD align = right>%d</TD>'count(array_unique($gridsquares)));
echo 
"<TD>&nbsp;&nbsp;&nbsp;</TD><TD align=left>QSLs Rcvd:</TD>";
echo 
"<TD align=right>$qsls_rcvd</TD></TR>";
echo 
"<TR><TD>CW QSOs:</TD><TD align = right>$cw_count</TD><TD></TD>";
echo 
"<TD>Satellite Contacts:</TD><TD align=right>$sat_count</TD>";
echo 
"<TD></TD><TD></TD><TD></TD><TD></TD><TD>Return rate:</TD>";
printf('<TD align=right>%0.1f%%</TD>'$qsls_rcvd $qsls_sent 100);
echo 
"</TR>";
echo 
"<TR><TD>PSK31 Contacts:</TD><TD align=right>$psk_count</TD></TR>";
echo 
"<TR><TD>RTTY Contacts:</TD><TD align=right>$rtty_count</TD></TR>";
echo 
"</TABLE><P>";

if (
file_exists($source)) {
    echo 
"This file was last modified: " date ("F d Y H:i:s."filemtime($source));
    echo 
" <a href=$source?source=1>(show source)</A>";
}

?>
<BR>
<address>Maintained by <a href="http://ccwf.cc.utexas.edu/~banks/">Roger Banks </a> 
( <a href="mailto:ke5aqd@ke5aqd.com">ke5aqd@ke5aqd.com</a> )</address>
<BR>
This page was generated on:  <?= date ("l, F d Y \a\\t h:i:s a."?> <BR>
<TABLE width=100%>
<TR>
<TD align="left"><A href="http://www.php.net">
    <img src="../images/logos/php_logo.gif" alt="php logo" border=0></A></TD>
<TD align="right"><A href="http://www.barebones.com">
   <img src="../images/logos/built_with_bbedit_01.gif" alt="bbedit logo" border=0></A></TD>
</TR>
</TABLE>
</body>
</html>