2013-02-16 16:41:40 +00:00
< ? php if ( ! defined ( 'BASEPATH' )) exit ( 'No direct script access allowed' );
class Lotw extends CI_Controller {
2020-08-26 21:26:37 +01:00
/*
|--------------------------------------------------------------------------
| Controller : Lotw
|--------------------------------------------------------------------------
2021-05-01 19:52:13 +02:00
|
2023-07-27 09:16:55 +02:00
| This Controller handles all things LoTW , upload and download .
2020-08-26 21:26:37 +01:00
|
|
| Note :
| If you plan on using any of the code within this class please credit
| Cloudlog or Peter , 2 M0SQL , a lot of hard work went into building the
| signing of files .
|
| Big Thanks to Rodrigo PY2RAF for all the help and information about OpenSSL
|
*/
2013-02-16 16:41:40 +00:00
/* Controls who can access the controller and its functions */
function __construct ()
{
parent :: __construct ();
$this -> load -> helper ( array ( 'form' , 'url' ));
2021-05-01 19:52:13 +02:00
2021-01-11 16:05:15 +00:00
// Load language files
$this -> lang -> load ( 'lotw' );
2013-02-16 16:41:40 +00:00
}
2016-01-09 23:50:42 +00:00
2020-08-13 17:28:22 +01:00
/*
|--------------------------------------------------------------------------
| Function : index
|--------------------------------------------------------------------------
2021-05-01 19:52:13 +02:00
|
2020-08-13 17:28:22 +01:00
| Default function for the controller which loads when doing / lotw
| this shows all the uploaded lotw p12 certificates the user has uploaded
|
*/
2020-08-13 17:24:07 +01:00
public function index () {
2020-09-02 14:48:13 +01:00
$this -> load -> model ( 'user_model' );
if ( ! $this -> user_model -> authorize ( 2 )) { $this -> session -> set_flashdata ( 'notice' , 'You\'re not allowed to do that!' ); redirect ( 'dashboard' ); }
2020-09-03 23:20:22 +01:00
2020-09-05 21:42:07 +01:00
// Fire OpenSSL missing error if not found
if ( ! extension_loaded ( 'openssl' )) {
echo " You must install php OpenSSL for LoTW functions to work " ;
}
2020-08-13 17:28:22 +01:00
// Load required models for page generation
2020-08-13 17:24:07 +01:00
$this -> load -> model ( 'LotwCert' );
2023-07-27 09:16:55 +02:00
// Get Array of the logged in users LoTW certs.
2020-08-13 17:24:07 +01:00
$data [ 'lotw_cert_results' ] = $this -> LotwCert -> lotw_certs ( $this -> session -> userdata ( 'user_id' ));
2020-08-13 17:28:22 +01:00
// Set Page Title
2020-08-13 17:24:07 +01:00
$data [ 'page_title' ] = " Logbook of the World " ;
2020-08-13 17:28:22 +01:00
// Load Views
2020-08-13 17:24:07 +01:00
$this -> load -> view ( 'interface_assets/header' , $data );
$this -> load -> view ( 'lotw_views/index' );
$this -> load -> view ( 'interface_assets/footer' );
}
2020-08-17 17:02:54 +01:00
/*
|--------------------------------------------------------------------------
| Function : cert_upload
|--------------------------------------------------------------------------
2021-05-01 19:52:13 +02:00
|
2020-08-17 17:02:54 +01:00
| Nothing fancy just shows the cert_upload form for uploading p12 files
|
*/
public function cert_upload () {
2020-09-02 14:48:13 +01:00
$this -> load -> model ( 'user_model' );
2020-12-28 13:42:26 +00:00
$this -> load -> model ( 'dxcc' );
2020-09-02 14:48:13 +01:00
if ( ! $this -> user_model -> authorize ( 2 )) { $this -> session -> set_flashdata ( 'notice' , 'You\'re not allowed to do that!' ); redirect ( 'dashboard' ); }
2020-12-28 13:42:26 +00:00
// Load DXCC Countrys List
$data [ 'dxcc_list' ] = $this -> dxcc -> list ();
2020-08-17 17:02:54 +01:00
// Set Page Title
$data [ 'page_title' ] = " Logbook of the World " ;
// Load Views
$this -> load -> view ( 'interface_assets/header' , $data );
$this -> load -> view ( 'lotw_views/upload_cert' , array ( 'error' => ' ' ));
2021-05-01 19:52:13 +02:00
$this -> load -> view ( 'interface_assets/footer' );
2020-08-17 17:02:54 +01:00
}
/*
|--------------------------------------------------------------------------
| Function : do_cert_upload
|--------------------------------------------------------------------------
2021-05-01 19:52:13 +02:00
|
2020-08-17 17:02:54 +01:00
| do_cert_upload is called from cert_upload form submit and handles uploading
| and processing of p12 files and storing the data into mysql
2026-02-18 15:51:19 +00:00
| Now supports HTMX requests for modal - based uploads
2020-08-17 17:02:54 +01:00
|
*/
public function do_cert_upload ()
{
2020-09-02 14:48:13 +01:00
$this -> load -> model ( 'user_model' );
2020-12-28 13:42:26 +00:00
$this -> load -> model ( 'dxcc' );
2020-09-02 14:48:13 +01:00
if ( ! $this -> user_model -> authorize ( 2 )) { $this -> session -> set_flashdata ( 'notice' , 'You\'re not allowed to do that!' ); redirect ( 'dashboard' ); }
2020-09-02 14:02:58 +01:00
2020-09-05 21:42:07 +01:00
// Fire OpenSSL missing error if not found
if ( ! extension_loaded ( 'openssl' )) {
echo " You must install php OpenSSL for LoTW functions to work " ;
}
2026-02-18 15:51:19 +00:00
// Check if this is an HTMX request
$is_htmx = $this -> input -> get_request_header ( 'HX-Request' );
2020-09-02 14:02:58 +01:00
// create folder to store certs while processing
if ( ! file_exists ( './uploads/lotw/certs' )) {
mkdir ( './uploads/lotw/certs' , 0755 , true );
}
2020-08-17 17:02:54 +01:00
$config [ 'upload_path' ] = './uploads/lotw/certs' ;
$config [ 'allowed_types' ] = 'p12' ;
$this -> load -> library ( 'upload' , $config );
if ( ! $this -> upload -> do_upload ( 'userfile' ))
{
// Upload of P12 Failed
2026-02-18 15:51:19 +00:00
$error = $this -> upload -> display_errors ();
2020-08-17 17:02:54 +01:00
2026-02-18 15:51:19 +00:00
// If HTMX request, return just the error message
if ( $is_htmx ) {
echo '<div class="alert alert-danger" role="alert">' . $error . '</div>' ;
return ;
}
2022-11-12 14:12:53 +00:00
2026-02-18 15:51:19 +00:00
// Otherwise load the full form page
$data = array ( 'error' => $error );
$data [ 'dxcc_list' ] = $this -> dxcc -> list ();
2020-08-17 17:02:54 +01:00
$data [ 'page_title' ] = " Logbook of the World " ;
$this -> load -> view ( 'interface_assets/header' , $data );
2026-02-18 15:51:19 +00:00
$this -> load -> view ( 'lotw_views/upload_cert' , $data );
2021-05-01 19:52:13 +02:00
$this -> load -> view ( 'interface_assets/footer' );
2020-08-17 17:02:54 +01:00
}
else
{
// Load database queries
$this -> load -> model ( 'LotwCert' );
//Upload of P12 successful
$data = array ( 'upload_data' => $this -> upload -> data ());
$info = $this -> decrypt_key ( $data [ 'upload_data' ][ 'full_path' ]);
2020-12-28 13:42:26 +00:00
// Check to see if certificate is already in the system
2023-04-19 15:32:32 +02:00
$new_certificate = $this -> LotwCert -> find_cert ( $info [ 'issued_callsign' ], $info [ 'dxcc-id' ], $this -> session -> userdata ( 'user_id' ));
2020-08-17 17:02:54 +01:00
2023-03-30 12:33:09 +02:00
if ( $new_certificate == 0 ) {
2020-08-17 17:02:54 +01:00
// New Certificate Store in Database
// Store Certificate Data into MySQL
2023-04-19 15:32:32 +02:00
$this -> LotwCert -> store_certificate ( $this -> session -> userdata ( 'user_id' ), $info [ 'issued_callsign' ], $info [ 'dxcc-id' ], $info [ 'validFrom' ], $info [ 'validTo_Date' ], $info [ 'qso-first-date' ], $info [ 'qso-end-date' ], $info [ 'pem_key' ], $info [ 'general_cert' ]);
2020-08-17 17:02:54 +01:00
// Cert success flash message
2026-02-18 15:51:19 +00:00
$success_msg = $info [ 'issued_callsign' ] . ' Certificate Imported.' ;
2020-08-17 17:02:54 +01:00
} else {
2023-03-30 12:33:09 +02:00
// Certificate is in the system time to update
2020-08-17 17:02:54 +01:00
2023-05-21 18:18:58 +02:00
$this -> LotwCert -> update_certificate ( $this -> session -> userdata ( 'user_id' ), $info [ 'issued_callsign' ], $info [ 'dxcc-id' ], $info [ 'validFrom' ], $info [ 'validTo_Date' ], $info [ 'qso-first-date' ], $info [ 'qso-end-date' ], $info [ 'pem_key' ], $info [ 'general_cert' ]);
2020-08-17 17:02:54 +01:00
// Cert success flash message
2026-02-18 15:51:19 +00:00
$success_msg = $info [ 'issued_callsign' ] . ' Certificate Updated.' ;
2020-08-17 17:02:54 +01:00
}
// p12 certificate processed time to delete the file
unlink ( $data [ 'upload_data' ][ 'full_path' ]);
2026-02-18 15:51:19 +00:00
// If HTMX request, return just the success message
if ( $is_htmx ) {
echo '<div class="alert alert-success" role="alert">' . $success_msg . '</div>' ;
return ;
}
// Otherwise load the full page
$this -> session -> set_flashdata ( 'Success' , $success_msg );
2023-07-27 09:16:55 +02:00
// Get Array of the logged in users LoTW certs.
2020-08-17 17:02:54 +01:00
$data [ 'lotw_cert_results' ] = $this -> LotwCert -> lotw_certs ( $this -> session -> userdata ( 'user_id' ));
// Set Page Title
$data [ 'page_title' ] = " Logbook of the World " ;
// Load Views
$this -> load -> view ( 'interface_assets/header' , $data );
$this -> load -> view ( 'lotw_views/index' );
$this -> load -> view ( 'interface_assets/footer' );
2026-02-18 15:51:19 +00:00
}
}
/*
|--------------------------------------------------------------------------
| Function : cert_table_refresh
|--------------------------------------------------------------------------
|
| Returns the certificate table for HTMX refresh after upload
|
*/
public function cert_table_refresh () {
$this -> load -> model ( 'user_model' );
if ( ! $this -> user_model -> authorize ( 2 )) { $this -> session -> set_flashdata ( 'notice' , 'You\'re not allowed to do that!' ); redirect ( 'dashboard' ); }
2020-08-17 17:02:54 +01:00
2026-02-18 15:51:19 +00:00
// Load model
$this -> load -> model ( 'LotwCert' );
2020-08-17 17:02:54 +01:00
2026-02-18 15:51:19 +00:00
// Get Array of the logged in users LoTW certs.
$data [ 'lotw_cert_results' ] = $this -> LotwCert -> lotw_certs ( $this -> session -> userdata ( 'user_id' ));
2020-08-17 17:02:54 +01:00
2026-02-18 15:51:19 +00:00
// Load just the cert table partial
$this -> load -> view ( 'lotw_views/cert_table' , $data );
}
2020-08-17 17:02:54 +01:00
2020-08-22 22:26:04 +01:00
/*
|--------------------------------------------------------------------------
| Function : lotw_upload
|--------------------------------------------------------------------------
2021-05-01 19:52:13 +02:00
|
2023-07-27 09:16:55 +02:00
| This function Uploads to LoTW
2020-08-22 22:26:04 +01:00
|
2025-10-11 15:17:51 +01:00
| Performance Optimization : Uses batch QSO updates instead of individual
| UPDATE queries to reduce database load during hourly uploads .
| Individual updates replaced with mark_lotw_sent_batch () for better performance .
|
2020-08-22 22:26:04 +01:00
*/
public function lotw_upload () {
2020-09-05 21:42:07 +01:00
2025-10-11 00:11:46 +01:00
$this -> load -> model ( 'user_model' );
$this -> user_model -> authorize ( 2 );
2023-07-12 15:56:12 +00:00
2025-10-11 00:11:46 +01:00
// Fire OpenSSL missing error if not found
if ( ! extension_loaded ( 'openssl' )) {
echo " You must install php OpenSSL for LoTW functions to work " ;
2020-09-05 21:42:07 +01:00
}
2020-09-05 21:42:55 +01:00
2025-10-11 00:11:46 +01:00
// Get Station Profile Data
$this -> load -> model ( 'Stations' );
2020-08-22 22:26:04 +01:00
2025-10-11 00:11:46 +01:00
if ( $this -> user_model -> authorize ( 2 )) {
$station_profiles = $this -> Stations -> all_of_user ( $this -> session -> userdata ( 'user_id' ));
$sync_user_id = $this -> session -> userdata ( 'user_id' );
} else {
$station_profiles = $this -> Stations -> all ();
$sync_user_id = null ;
2023-07-12 15:56:12 +00:00
}
2020-08-22 22:26:04 +01:00
2020-09-05 21:42:55 +01:00
// Build TQ8 Outputs
2023-07-13 07:13:56 +00:00
if ( $station_profiles -> num_rows () >= 1 ) {
2020-08-26 21:04:17 +01:00
2023-07-13 07:13:56 +00:00
foreach ( $station_profiles -> result () as $station_profile ) {
2025-10-11 15:17:51 +01:00
// Array of QSO IDs being Uploaded for this station profile
$qso_id_array = array ();
2020-08-22 22:26:04 +01:00
2025-10-11 00:11:38 +01:00
// Get Certificate Data
$this -> load -> model ( 'LotwCert' );
$data [ 'station_profile' ] = $station_profile ;
$data [ 'lotw_cert_info' ] = $this -> LotwCert -> lotw_cert_details ( $station_profile -> station_callsign , $station_profile -> station_dxcc );
// If Station Profile has no LoTW Cert continue on.
if ( ! isset ( $data [ 'lotw_cert_info' ] -> cert_dxcc_id )) {
2023-07-13 07:13:56 +00:00
continue ;
}
2020-09-02 11:45:50 +01:00
2023-07-13 07:13:56 +00:00
// Check if LoTW certificate itself is valid
// Validty of QSO dates will be checked later
$current_date = date ( 'Y-m-d H:i:s' );
if ( $current_date <= $data [ 'lotw_cert_info' ] -> date_created ) {
echo $data [ 'lotw_cert_info' ] -> callsign . " : LoTW certificate not valid yet! " ;
continue ;
}
if ( $current_date >= $data [ 'lotw_cert_info' ] -> date_expires ) {
echo $data [ 'lotw_cert_info' ] -> callsign . " : LoTW certificate expired! " ;
continue ;
}
2022-08-24 16:04:26 +02:00
2025-10-11 00:11:38 +01:00
// Get QSOs
2020-08-25 17:50:52 +01:00
2025-10-11 00:11:38 +01:00
$this -> load -> model ( 'Logbook_model' );
2020-08-25 17:50:52 +01:00
2025-10-11 00:11:38 +01:00
$data [ 'qsos' ] = $this -> Logbook_model -> get_lotw_qsos_to_upload ( $data [ 'station_profile' ] -> station_id , $data [ 'lotw_cert_info' ] -> qso_start_date , $data [ 'lotw_cert_info' ] -> qso_end_date );
// Nothing to upload
if ( empty ( $data [ 'qsos' ] -> result ())){
if ( $this -> user_model -> authorize ( 2 )) { // Only be verbose if we have a session
echo $station_profile -> station_callsign . " ( " . $station_profile -> station_profile_name . " ) No QSOs to Upload <br> " ;
2021-05-01 19:52:13 +02:00
}
2023-07-13 07:13:56 +00:00
continue ;
}
2020-09-02 12:02:29 +01:00
2023-07-13 07:13:56 +00:00
foreach ( $data [ 'qsos' ] -> result () as $temp_qso ) {
array_push ( $qso_id_array , $temp_qso -> COL_PRIMARY_KEY );
}
2020-08-26 21:04:17 +01:00
2023-07-13 07:13:56 +00:00
// Build File to save
2025-10-11 00:11:46 +01:00
$adif_to_save = $this -> load -> view ( 'lotw_views/adif_views/adif_export' , $data , TRUE );
2020-09-06 20:33:12 +01:00
2023-07-13 07:13:56 +00:00
// create folder to store upload file
if ( ! file_exists ( './uploads/lotw' )) {
2025-10-11 00:11:46 +01:00
mkdir ( './uploads/lotw' , 0775 , true );
2023-07-13 07:13:56 +00:00
}
2020-10-21 16:04:14 -04:00
2023-07-13 07:13:56 +00:00
// Build Filename
$filename_for_saving = './uploads/lotw/' . preg_replace ( '/[^a-z0-9]+/' , '-' , strtolower ( $data [ 'lotw_cert_info' ] -> callsign )) . " - " . date ( " Y-m-d-H-i-s " ) . " -cloudlog.tq8 " ;
2020-08-26 21:04:17 +01:00
2023-07-13 07:13:56 +00:00
$gzdata = gzencode ( $adif_to_save , 9 );
$fp = fopen ( $filename_for_saving , " w " );
2025-10-11 00:11:46 +01:00
fwrite ( $fp , $gzdata );
2023-07-13 07:13:56 +00:00
fclose ( $fp );
2020-08-26 21:04:17 +01:00
2023-07-13 07:13:56 +00:00
//The URL that accepts the file upload.
$url = 'https://lotw.arrl.org/lotw/upload' ;
2021-05-01 19:52:13 +02:00
2023-07-13 07:13:56 +00:00
//The name of the field for the uploaded file.
$uploadFieldName = 'upfile' ;
2021-05-01 19:52:13 +02:00
2023-07-13 07:13:56 +00:00
//The full path to the file that you want to upload
$filePath = realpath ( $filename_for_saving );
2021-05-01 19:52:13 +02:00
2023-07-13 07:13:56 +00:00
//Initiate cURL
$ch = curl_init ();
2021-05-01 19:52:13 +02:00
2023-07-13 07:13:56 +00:00
//Set the URL
curl_setopt ( $ch , CURLOPT_URL , $url );
2021-05-01 19:52:13 +02:00
2023-07-13 07:13:56 +00:00
//Set the HTTP request to POST
curl_setopt ( $ch , CURLOPT_POST , true );
2021-05-01 19:52:13 +02:00
2023-07-13 07:13:56 +00:00
//Tell cURL to return the output as a string.
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
2021-05-01 19:52:13 +02:00
2024-05-13 16:39:59 +02:00
//Use the recommended way, creating a CURLFile object.
$uploadfile = curl_file_create ( $filePath );
$uploadfile -> setPostFilename ( basename ( $filePath ));
2024-05-13 16:39:31 +02:00
2023-07-13 07:13:56 +00:00
//Setup our POST fields
$postFields = array (
2024-05-13 16:39:31 +02:00
$uploadFieldName => $uploadfile
2023-07-13 07:13:56 +00:00
);
2021-05-01 19:52:13 +02:00
2023-07-13 07:13:56 +00:00
curl_setopt ( $ch , CURLOPT_POSTFIELDS , $postFields );
2021-05-01 19:52:13 +02:00
2023-07-13 07:13:56 +00:00
//Execute the request
$result = curl_exec ( $ch );
2021-05-01 19:52:13 +02:00
2023-07-13 07:13:56 +00:00
//If an error occured, throw an exception
//with the error message.
if ( curl_errno ( $ch )){
throw new Exception ( curl_error ( $ch ));
2024-05-15 22:36:37 +01:00
2024-05-15 22:36:07 +01:00
// Upload of TQ8 Failed for unknown reason
echo $station_profile -> station_callsign . " ( " . $station_profile -> station_profile_name . " ) Upload Failed " . " <br> " ;
2023-07-13 07:13:56 +00:00
}
2021-05-01 19:52:13 +02:00
2025-07-17 16:50:39 +01:00
$pos = strpos ( $result , " <!-- .UPL. accepted --> " );
2020-08-26 21:04:17 +01:00
2023-07-13 07:13:56 +00:00
if ( $pos === false ) {
// Upload of TQ8 Failed for unknown reason
echo $station_profile -> station_callsign . " ( " . $station_profile -> station_profile_name . " ) Upload Failed " . " <br> " ;
} else {
// Upload of TQ8 was successfull
2020-08-26 21:04:17 +01:00
2023-07-13 07:13:56 +00:00
echo " Upload Successful - " . $filename_for_saving . " <br> " ;
2020-08-26 21:04:17 +01:00
2025-10-11 15:17:51 +01:00
// Use transaction for data consistency
$this -> db -> trans_begin ();
try {
$this -> LotwCert -> last_upload ( $data [ 'lotw_cert_info' ] -> lotw_cert_id );
// Mark QSOs as Sent (batch update for performance)
if ( ! empty ( $qso_id_array )) {
$affected_rows = $this -> Logbook_model -> mark_lotw_sent_batch ( $qso_id_array );
if ( $this -> user_model -> authorize ( 2 )) {
echo " Marked " . $affected_rows . " QSOs as sent to LoTW<br> " ;
}
}
2020-08-26 21:20:58 +01:00
2025-10-11 15:17:51 +01:00
$this -> db -> trans_commit ();
} catch ( Exception $e ) {
$this -> db -> trans_rollback ();
echo " Database update failed for " . $station_profile -> station_callsign . " : " . $e -> getMessage () . " <br> " ;
2020-08-26 21:04:17 +01:00
}
2020-08-22 22:26:04 +01:00
}
2023-07-13 07:13:56 +00:00
// Delete TQ8 File - This is done regardless of whether upload was succcessful
unlink ( realpath ( $filename_for_saving ));
2020-08-22 22:26:04 +01:00
}
2023-07-13 07:13:56 +00:00
} else {
2023-07-27 09:16:55 +02:00
echo " No Station Profiles found to upload to LoTW " ;
2023-07-13 07:13:56 +00:00
}
2020-08-22 22:26:04 +01:00
2020-09-06 17:35:45 +01:00
/*
| Download QSO Matches from LoTW
2023-07-13 07:13:56 +00:00
*/
if ( $this -> user_model -> authorize ( 2 )) {
2020-09-08 00:12:11 +01:00
echo " <br><br> " ;
2023-07-13 07:13:56 +00:00
$sync_user_id = $this -> session -> userdata ( 'user_id' );
} else {
$sync_user_id = null ;
}
echo $this -> lotw_download ( $sync_user_id );
2020-08-22 22:26:04 +01:00
}
2020-08-17 17:02:54 +01:00
/*
|--------------------------------------------------------------------------
| Function : delete_cert
|--------------------------------------------------------------------------
2021-05-01 19:52:13 +02:00
|
2023-07-27 09:16:55 +02:00
| Deletes LoTW certificate from the MySQL table
2020-08-17 17:02:54 +01:00
|
*/
public function delete_cert ( $cert_id ) {
2020-09-02 14:48:13 +01:00
$this -> load -> model ( 'user_model' );
if ( ! $this -> user_model -> authorize ( 2 )) { $this -> session -> set_flashdata ( 'notice' , 'You\'re not allowed to do that!' ); redirect ( 'dashboard' ); }
2020-08-17 17:02:54 +01:00
$this -> load -> model ( 'LotwCert' );
2023-03-30 12:33:09 +02:00
$this -> LotwCert -> delete_certificate ( $this -> session -> userdata ( 'user_id' ), $cert_id );
2020-08-17 17:02:54 +01:00
2023-03-30 12:33:09 +02:00
$this -> session -> set_flashdata ( 'Success' , 'Certificate Deleted.' );
2020-08-17 17:02:54 +01:00
redirect ( '/lotw/' );
}
2025-08-22 17:15:51 +01:00
/*
|--------------------------------------------------------------------------
| Function : toggle_archive_cert
|--------------------------------------------------------------------------
|
| Toggles the archive status of a LoTW certificate
|
*/
public function toggle_archive_cert ( $cert_id ) {
$this -> load -> model ( 'user_model' );
if ( ! $this -> user_model -> authorize ( 2 )) { $this -> session -> set_flashdata ( 'notice' , 'You\'re not allowed to do that!' ); redirect ( 'dashboard' ); }
$this -> load -> model ( 'LotwCert' );
$result = $this -> LotwCert -> toggle_archive_certificate ( $this -> session -> userdata ( 'user_id' ), $cert_id );
if ( $result [ 'archived' ]) {
$this -> session -> set_flashdata ( 'Success' , 'Certificate Archived.' );
} else {
$this -> session -> set_flashdata ( 'Success' , 'Certificate Unarchived.' );
}
redirect ( '/lotw/' );
}
2020-08-17 17:02:54 +01:00
/*
|--------------------------------------------------------------------------
| Function : decrypt_key
|--------------------------------------------------------------------------
2021-05-01 19:52:13 +02:00
|
2020-08-17 17:02:54 +01:00
| Accepts p12 file and optional password and encrypts the file returning
2023-07-27 09:16:55 +02:00
| the required fields for LoTW and the PEM Key
2020-08-17 17:02:54 +01:00
|
*/
public function decrypt_key ( $file , $password = " " ) {
2020-09-02 14:48:13 +01:00
$this -> load -> model ( 'user_model' );
if ( ! $this -> user_model -> authorize ( 2 )) { $this -> session -> set_flashdata ( 'notice' , 'You\'re not allowed to do that!' ); redirect ( 'dashboard' ); }
2020-08-13 23:03:25 +01:00
$results = array ();
2020-08-17 17:02:54 +01:00
$password = $password ; // Only needed if 12 has a password set
$filename = file_get_contents ( 'file://' . $file );
2020-08-13 23:03:25 +01:00
$worked = openssl_pkcs12_read ( $filename , $results , $password );
2020-08-26 16:31:35 +01:00
$data [ 'general_cert' ] = $results [ 'cert' ];
2020-08-13 23:03:25 +01:00
if ( $worked ) {
2020-08-13 23:34:10 +01:00
// Reading p12 successful
$new_password = " cloudlog " ; // set default password
2020-08-13 23:03:25 +01:00
$result = null ;
$worked = openssl_pkey_export ( $results [ 'pkey' ], $result , $new_password );
2020-08-26 16:31:35 +01:00
2020-08-13 23:03:25 +01:00
if ( $worked ) {
2020-08-13 23:34:10 +01:00
// Store PEM Key in Array
$data [ 'pem_key' ] = $result ;
2020-08-13 23:03:25 +01:00
} else {
2020-08-17 17:02:54 +01:00
// Error Log Error Message
log_message ( 'error' , openssl_error_string ());
2023-07-27 09:16:55 +02:00
// Set warning message redirect to LoTW main page
2020-08-17 17:02:54 +01:00
$this -> session -> set_flashdata ( 'Warning' , openssl_error_string ());
redirect ( '/lotw/' );
2020-08-13 23:03:25 +01:00
}
} else {
2020-08-17 17:02:54 +01:00
// Reading p12 failed log error message
log_message ( 'error' , openssl_error_string ());
2023-07-27 09:16:55 +02:00
// Set warning message redirect to LoTW main page
2020-08-17 17:02:54 +01:00
$this -> session -> set_flashdata ( 'Warning' , openssl_error_string ());
redirect ( '/lotw/' );
2020-08-13 23:03:25 +01:00
}
2020-08-13 23:34:10 +01:00
// Read Cert Data
$certdata = openssl_x509_parse ( $results [ 'cert' ], 0 );
2023-11-24 13:08:40 +01:00
2020-08-13 23:34:10 +01:00
// Store Variables
$data [ 'issued_callsign' ] = $certdata [ 'subject' ][ 'undefined' ];
$data [ 'issued_name' ] = $certdata [ 'subject' ][ 'commonName' ];
2022-08-24 12:16:41 +02:00
$data [ 'validFrom' ] = date ( 'Y-m-d H:i:s' , $certdata [ 'validFrom_time_t' ]);
$data [ 'validTo_Date' ] = date ( 'Y-m-d H:i:s' , $certdata [ 'validTo_time_t' ]);
2022-08-24 13:13:55 +02:00
// https://oidref.com/1.3.6.1.4.1.12348.1
2022-08-24 12:16:41 +02:00
$data [ 'qso-first-date' ] = $certdata [ 'extensions' ][ '1.3.6.1.4.1.12348.1.2' ];
$data [ 'qso-end-date' ] = $certdata [ 'extensions' ][ '1.3.6.1.4.1.12348.1.3' ];
2023-04-19 15:32:32 +02:00
$data [ 'dxcc-id' ] = $certdata [ 'extensions' ][ '1.3.6.1.4.1.12348.1.4' ];
2020-08-13 23:34:10 +01:00
2020-08-17 17:02:54 +01:00
return $data ;
2020-08-13 23:03:25 +01:00
}
2021-05-01 19:52:13 +02:00
2020-09-06 20:38:45 +01:00
/*
|--------------------------------------------------------------------------
| Function : loadFromFile
|--------------------------------------------------------------------------
2021-05-01 19:52:13 +02:00
|
2020-09-06 20:38:45 +01:00
| $filepath is the ADIF file , $display_view is used to hide the output if its internal script
|
| Internal function that takes the LoTW ADIF and imports into the log
|
*/
2020-09-06 20:27:23 +01:00
private function loadFromFile ( $filepath , $display_view = " TRUE " )
2013-02-23 16:42:18 -07:00
{
2020-07-01 00:34:51 -06:00
2013-03-02 14:24:16 -06:00
// Figure out how we should be marking QSLs confirmed via LoTW
$query = $query = $this -> db -> query ( 'SELECT lotw_rcvd_mark FROM config' );
$q = $query -> row ();
$config [ 'lotw_rcvd_mark' ] = $q -> lotw_rcvd_mark ;
2016-01-09 23:50:42 +00:00
2013-02-23 18:40:06 -06:00
ini_set ( 'memory_limit' , '-1' );
2013-02-23 16:42:18 -07:00
set_time_limit ( 0 );
$this -> load -> library ( 'adif_parser' );
$this -> adif_parser -> load_from_file ( $filepath );
$this -> adif_parser -> initialize ();
2020-08-10 23:07:55 +01:00
$tableheaders = " <table width= \" 100% \" > " ;
2013-11-15 15:28:56 -06:00
$tableheaders .= " <tr class= \" titles \" > " ;
2020-09-06 16:37:03 +01:00
$tableheaders .= " <td>Station Callsign</td> " ;
2013-11-15 15:28:56 -06:00
$tableheaders .= " <td>QSO Date</td> " ;
$tableheaders .= " <td>Call</td> " ;
$tableheaders .= " <td>Mode</td> " ;
$tableheaders .= " <td>LoTW QSL Received</td> " ;
$tableheaders .= " <td>Date LoTW Confirmed</td> " ;
2020-08-10 23:07:55 +01:00
$tableheaders .= " <td>State</td> " ;
2021-07-27 18:49:54 -04:00
$tableheaders .= " <td>Gridsquare</td> " ;
2022-05-09 14:44:32 +02:00
$tableheaders .= " <td>IOTA</td> " ;
2013-11-15 15:28:56 -06:00
$tableheaders .= " <td>Log Status</td> " ;
2016-01-09 23:53:50 +00:00
$tableheaders .= " </tr> " ;
2013-11-15 15:28:56 -06:00
$table = " " ;
2026-02-11 11:14:59 +00:00
$batch_updates = array (); // Collect all updates for batch processing
$table_rows = array (); // Collect table rows for later rendering
2026-02-17 15:35:06 +00:00
$found_count = 0 ;
2026-02-11 11:14:59 +00:00
// First pass: collect all records for batch processing
2013-11-15 15:28:56 -06:00
while ( $record = $this -> adif_parser -> get_record ())
2013-02-23 16:42:18 -07:00
{
2016-01-09 23:50:42 +00:00
2013-11-15 15:28:56 -06:00
$time_on = date ( 'Y-m-d' , strtotime ( $record [ 'qso_date' ])) . " " . date ( 'H:i' , strtotime ( $record [ 'time_on' ]));
2016-01-09 23:50:42 +00:00
2013-11-15 15:28:56 -06:00
$qsl_date = date ( 'Y-m-d' , strtotime ( $record [ 'qslrdate' ])) . " " . date ( 'H:i' , strtotime ( $record [ 'qslrdate' ]));
2013-02-23 16:42:18 -07:00
2013-11-15 15:28:56 -06:00
if ( isset ( $record [ 'time_off' ])) {
$time_off = date ( 'Y-m-d' , strtotime ( $record [ 'qso_date' ])) . " " . date ( 'H:i' , strtotime ( $record [ 'time_off' ]));
} else {
2016-01-09 23:50:42 +00:00
$time_off = date ( 'Y-m-d' , strtotime ( $record [ 'qso_date' ])) . " " . date ( 'H:i' , strtotime ( $record [ 'time_on' ]));
2013-11-15 15:28:56 -06:00
}
2016-01-09 23:50:42 +00:00
2013-11-15 15:28:56 -06:00
// If we have a positive match from LoTW, record it in the DB according to the user's preferences
if ( $record [ 'qsl_rcvd' ] == " Y " )
{
$record [ 'qsl_rcvd' ] = $config [ 'lotw_rcvd_mark' ];
}
2016-01-09 23:50:42 +00:00
2023-07-05 17:13:17 +00:00
$status = $this -> logbook_model -> import_check ( $time_on , $record [ 'call' ], $record [ 'band' ], $record [ 'mode' ], $record [ 'station_callsign' ]);
2020-05-01 13:29:02 +02:00
2023-07-12 10:48:22 +02:00
if ( $status [ 0 ] == " Found " ) {
2026-02-17 15:35:06 +00:00
$found_count ++ ;
2026-02-11 11:14:59 +00:00
$state = isset ( $record [ 'state' ]) ? $record [ 'state' ] : " " ;
$qsl_gridsquare = isset ( $record [ 'gridsquare' ]) ? $record [ 'gridsquare' ] : " " ;
$qsl_vucc_grids = isset ( $record [ 'vucc_grids' ]) ? $record [ 'vucc_grids' ] : " " ;
$iota = isset ( $record [ 'iota' ]) ? $record [ 'iota' ] : " " ;
$cnty = isset ( $record [ 'cnty' ]) ? $record [ 'cnty' ] : " " ;
$cqz = isset ( $record [ 'cqz' ]) ? $record [ 'cqz' ] : " " ;
$ituz = isset ( $record [ 'ituz' ]) ? $record [ 'ituz' ] : " " ;
// Add to batch update array
$batch_updates [] = array (
2026-02-17 15:28:53 +00:00
'primary_key' => $status [ 1 ],
2026-02-11 11:14:59 +00:00
'datetime' => $time_on ,
'callsign' => $record [ 'call' ],
'band' => $record [ 'band' ],
'qsl_date' => $qsl_date ,
'qsl_status' => $record [ 'qsl_rcvd' ],
'state' => $state ,
'qsl_gridsquare' => $qsl_gridsquare ,
'qsl_vucc_grids' => $qsl_vucc_grids ,
'iota' => $iota ,
'cnty' => $cnty ,
'cqz' => $cqz ,
'ituz' => $ituz ,
'station_callsign' => $record [ 'station_callsign' ]
);
$table_rows [] = array (
'station_callsign' => $record [ 'station_callsign' ],
'time_on' => $time_on ,
'call' => $record [ 'call' ],
'mode' => $record [ 'mode' ],
'qsl_rcvd' => $record [ 'qsl_rcvd' ],
'qsl_date' => $qsl_date ,
'state' => $state ,
'gridsquare' => ( $qsl_gridsquare != '' ? $qsl_gridsquare : $qsl_vucc_grids ),
'iota' => $iota ,
'status' => $status [ 0 ],
'found' => true
);
} else {
$table_rows [] = array (
'station_callsign' => $record [ 'station_callsign' ],
'time_on' => $time_on ,
'call' => $record [ 'call' ],
'mode' => $record [ 'mode' ],
'qsl_rcvd' => $record [ 'qsl_rcvd' ],
'status' => $status [ 0 ],
'found' => false
);
}
}
// Batch update all LOTW confirmations in one operation
$lotw_status = " No updates " ;
if ( ! empty ( $batch_updates )) {
$result = $this -> logbook_model -> lotw_update_batch ( $batch_updates );
2026-02-17 15:35:06 +00:00
$already_confirmed = max ( 0 , $found_count - $result [ 'updated' ]);
$lotw_status = " Found: { $found_count } QSOs, Updated: { $result [ 'updated' ] } QSOs, Already confirmed: { $already_confirmed } QSOs, Gridsquares updated: { $result [ 'gridsquare_updated' ] } " ;
2026-02-11 11:14:59 +00:00
log_message ( 'info' , 'LoTW Download: ' . $lotw_status );
}
// Build table from collected rows
foreach ( $table_rows as $row ) {
if ( $row [ 'found' ]) {
2023-07-12 11:15:14 +02:00
$table .= " <tr> " ;
2026-02-11 11:14:59 +00:00
$table .= " <td> " . $row [ 'station_callsign' ] . " </td> " ;
$table .= " <td> " . $row [ 'time_on' ] . " </td> " ;
$table .= " <td> " . $row [ 'call' ] . " </td> " ;
$table .= " <td> " . $row [ 'mode' ] . " </td> " ;
$table .= " <td> " . $row [ 'qsl_rcvd' ] . " </td> " ;
$table .= " <td> " . $row [ 'qsl_date' ] . " </td> " ;
$table .= " <td> " . $row [ 'state' ] . " </td> " ;
$table .= " <td> " . $row [ 'gridsquare' ] . " </td> " ;
$table .= " <td> " . $row [ 'iota' ] . " </td> " ;
$table .= " <td>QSO Record: " . $row [ 'status' ] . " </td> " ;
2023-07-12 11:15:14 +02:00
$table .= " </tr> " ;
} else {
$table .= " <tr> " ;
2026-02-11 11:14:59 +00:00
$table .= " <td> " . $row [ 'station_callsign' ] . " </td> " ;
$table .= " <td> " . $row [ 'time_on' ] . " </td> " ;
$table .= " <td> " . $row [ 'call' ] . " </td> " ;
$table .= " <td> " . $row [ 'mode' ] . " </td> " ;
$table .= " <td> " . $row [ 'qsl_rcvd' ] . " </td> " ;
2023-07-12 10:48:22 +02:00
$table .= " <td></td> " ;
2023-07-12 11:15:14 +02:00
$table .= " <td></td> " ;
$table .= " <td></td> " ;
$table .= " <td></td> " ;
2026-02-11 11:14:59 +00:00
$table .= " <td>QSO Record: " . $row [ 'status' ] . " </td> " ;
2023-07-12 11:15:14 +02:00
$table .= " </tr> " ;
}
2013-11-15 15:28:56 -06:00
}
2016-01-09 23:50:42 +00:00
2013-11-15 15:28:56 -06:00
if ( $table != " " )
{
$table .= " </table> " ;
2026-02-17 15:33:41 +00:00
$table .= '<div class="mt-2"><strong>LoTW Status:</strong> ' . $lotw_status . '</div>' ;
2013-11-15 15:28:56 -06:00
$data [ 'lotw_table_headers' ] = $tableheaders ;
$data [ 'lotw_table' ] = $table ;
}
2016-01-09 23:50:42 +00:00
2013-02-23 18:40:06 -06:00
unlink ( $filepath );
2013-02-23 16:42:18 -07:00
2023-07-12 15:56:12 +00:00
$this -> load -> model ( 'user_model' );
if ( $this -> user_model -> authorize ( 2 )) { // Only Output results if authorized User
if ( isset ( $data [ 'lotw_table_headers' ])) {
if ( $display_view == TRUE ) {
$data [ 'page_title' ] = " LoTW ADIF Information " ;
$this -> load -> view ( 'interface_assets/header' , $data );
$this -> load -> view ( 'lotw/analysis' );
$this -> load -> view ( 'interface_assets/footer' );
} else {
return $tableheaders . $table ;
}
2020-09-06 20:26:19 +01:00
} else {
2023-07-12 15:56:12 +00:00
echo " Downloaded LoTW report contains no matches. " ;
2020-09-06 20:26:19 +01:00
}
2020-09-06 17:44:06 +01:00
}
2013-02-23 16:42:18 -07:00
}
2013-02-16 16:41:40 +00:00
2020-09-06 20:38:45 +01:00
/*
|--------------------------------------------------------------------------
| Function : lotw_download
|--------------------------------------------------------------------------
2021-05-01 19:52:13 +02:00
|
| Collects users with LoTW usernames and passwords and runs through them
2020-09-06 20:38:45 +01:00
| downloading matching QSOs .
|
*/
2023-07-12 15:56:12 +00:00
function lotw_download ( $sync_user_id = null ) {
2025-10-11 00:11:46 +01:00
$this -> load -> model ( 'user_model' );
$this -> load -> model ( 'logbook_model' );
$query = $this -> user_model -> get_all_lotw_users ();
2020-09-06 16:32:02 +01:00
2020-09-06 16:55:30 +01:00
if ( $query -> num_rows () >= 1 ) {
2023-11-24 13:49:30 +01:00
$result = '' ;
2023-11-30 12:26:31 +01:00
2025-10-11 00:11:46 +01:00
// Get URL for downloading LoTW
$url_query = $this -> db -> query ( 'SELECT lotw_download_url FROM config' );
$q = $url_query -> row ();
$lotw_base_url = $q -> lotw_download_url ;
2023-11-30 12:26:31 +01:00
2023-07-12 15:56:12 +00:00
foreach ( $query -> result () as $user ) {
2025-10-11 00:11:46 +01:00
if ( ( $sync_user_id != null ) && ( $sync_user_id != $user -> user_id ) ) { continue ; }
2020-09-06 16:26:15 +01:00
2023-11-24 13:49:30 +01:00
// Validate that LoTW credentials are not empty
2025-10-11 00:11:46 +01:00
// TODO: We don't actually see the error message
2023-11-24 13:49:30 +01:00
if ( $user -> user_lotw_password == '' ) {
2025-10-11 00:11:46 +01:00
$result = " You have not defined your ARRL LoTW credentials! " ;
2023-11-24 13:49:30 +01:00
continue ;
}
2020-09-06 16:55:30 +01:00
$config [ 'upload_path' ] = './uploads/' ;
$file = $config [ 'upload_path' ] . 'lotwreport_download.adi' ;
2023-04-11 22:40:53 +02:00
if ( file_exists ( $file ) && ! is_writable ( $file )) {
2023-11-24 13:49:30 +01:00
$result = " Temporary download file " . $file . " is not writable. Aborting! " ;
continue ;
2023-04-11 22:40:53 +02:00
}
2020-09-06 16:55:30 +01:00
2025-10-13 16:46:53 +01:00
// Get credentials for LoTW - use rawurlencode to prevent & issues
$data [ 'user_lotw_name' ] = rawurlencode ( $user -> user_lotw_name );
$data [ 'user_lotw_password' ] = rawurlencode ( $user -> user_lotw_password );
2020-09-06 16:55:30 +01:00
2025-10-11 00:11:38 +01:00
$lotw_last_qsl_date = date ( 'Y-m-d' , strtotime ( $this -> logbook_model -> lotw_last_qsl_date ( $user -> user_id )));
2020-09-06 16:26:15 +01:00
2020-09-06 16:55:30 +01:00
// Build URL for LoTW report file
2023-11-30 13:15:36 +01:00
$lotw_url = $lotw_base_url . " ? " ;
2020-09-06 16:55:30 +01:00
$lotw_url .= " login= " . $data [ 'user_lotw_name' ];
$lotw_url .= " &password= " . $data [ 'user_lotw_password' ];
$lotw_url .= " &qso_query=1&qso_qsl='yes'&qso_qsldetail='yes'&qso_mydetail='yes' " ;
2025-10-13 16:46:53 +01:00
$lotw_url .= " &qso_qslsince= " . $lotw_last_qsl_date ;
2025-10-11 00:11:38 +01:00
2025-10-13 16:46:53 +01:00
// Debug logging
log_message ( 'debug' , 'LoTW URL being requested: ' . $lotw_url );
2020-09-06 16:26:15 +01:00
2025-10-11 00:11:38 +01:00
if ( ! is_writable ( dirname ( $file ))) {
$result = " Temporary download directory " . dirname ( $file ) . " is not writable. Aborting! " ;
2023-07-13 07:13:56 +00:00
continue ;
2023-04-11 22:40:53 +02:00
}
2025-10-13 16:46:53 +01:00
// Replace file_get_contents with cURL for better error handling
$ch = curl_init ();
curl_setopt ( $ch , CURLOPT_URL , $lotw_url );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
curl_setopt ( $ch , CURLOPT_TIMEOUT , 60 );
curl_setopt ( $ch , CURLOPT_CONNECTTIMEOUT , 30 );
curl_setopt ( $ch , CURLOPT_FOLLOWLOCATION , true );
curl_setopt ( $ch , CURLOPT_SSL_VERIFYPEER , true );
curl_setopt ( $ch , CURLOPT_SSL_VERIFYHOST , 2 );
curl_setopt ( $ch , CURLOPT_USERAGENT , 'Cloudlog LoTW Client/1.0' );
curl_setopt ( $ch , CURLOPT_HTTPHEADER , array (
'Accept: text/plain,*/*' ,
'Accept-Language: en-US,en;q=0.9'
));
2025-10-13 22:07:00 +01:00
$max_retries = 3 ;
$retry_delay = 2 ; // seconds
$response = false ;
$curl_error = '' ;
$http_code = 0 ;
for ( $attempt = 1 ; $attempt <= $max_retries ; $attempt ++ ) {
$response = curl_exec ( $ch );
$http_code = curl_getinfo ( $ch , CURLINFO_HTTP_CODE );
$curl_error = curl_error ( $ch );
// If successful or non-network error, break out of retry loop
if ( $response !== false && empty ( $curl_error )) {
break ;
}
// Log retry attempt
if ( $attempt < $max_retries ) {
log_message ( 'debug' , " LoTW download attempt { $attempt } failed for user " . $data [ 'user_lotw_name' ] . " : " . $curl_error . " - retrying in { $retry_delay } seconds " );
sleep ( $retry_delay );
// Exponential backoff - increase delay for next retry
$retry_delay *= 2 ;
}
}
2025-10-13 16:46:53 +01:00
curl_close ( $ch );
2025-10-13 22:07:00 +01:00
// Check for cURL errors after all retries
2025-10-13 16:46:53 +01:00
if ( $response === false || ! empty ( $curl_error )) {
2025-10-13 22:07:00 +01:00
$result = " LoTW download failed for user " . $data [ 'user_lotw_name' ] . " after { $max_retries } attempts: " . $curl_error ;
log_message ( 'error' , 'LoTW cURL error after retries: ' . $curl_error );
2025-10-13 16:46:53 +01:00
continue ;
}
// Check HTTP response code
if ( $http_code !== 200 ) {
$result = " LoTW download failed for user " . $data [ 'user_lotw_name' ] . " : HTTP " . $http_code ;
log_message ( 'error' , 'LoTW HTTP error: ' . $http_code );
continue ;
}
// Save the response to file
if ( file_put_contents ( $file , $response ) === false ) {
$result = " Failed to write LoTW response to file for user " . $data [ 'user_lotw_name' ];
continue ;
}
2025-10-11 00:11:38 +01:00
if ( file_get_contents ( $file , false , null , 0 , 39 ) != " ARRL Logbook of the World Status Report " ) {
2023-11-24 13:49:30 +01:00
$result = " LoTW downloading failed for User " . $data [ 'user_lotw_name' ] . " either due to it being down or incorrect logins. " ;
2023-07-13 07:13:56 +00:00
continue ;
2023-04-11 23:19:32 +02:00
}
2020-09-06 16:55:30 +01:00
2025-10-11 00:11:38 +01:00
ini_set ( 'memory_limit' , '-1' );
$result = $this -> loadFromFile ( $file , false );
2023-11-24 13:49:30 +01:00
}
return $result ;
2020-09-06 16:55:30 +01:00
} else {
2023-07-27 09:16:55 +02:00
return " No LoTW User details found to carry out matches. " ;
2020-09-06 16:55:30 +01:00
}
2020-09-06 16:26:15 +01:00
}
2016-01-09 23:50:42 +00:00
public function import () {
2020-07-01 00:34:51 -06:00
$this -> load -> model ( 'user_model' );
if ( ! $this -> user_model -> authorize ( 2 )) { $this -> session -> set_flashdata ( 'notice' , 'You\'re not allowed to do that!' ); redirect ( 'dashboard' ); }
2013-02-16 16:41:40 +00:00
$data [ 'page_title' ] = " LoTW ADIF Import " ;
$config [ 'upload_path' ] = './uploads/' ;
$config [ 'allowed_types' ] = 'adi|ADI' ;
2016-01-09 23:50:42 +00:00
2013-02-16 16:41:40 +00:00
$this -> load -> library ( 'upload' , $config );
2016-01-09 23:50:42 +00:00
2013-02-23 13:25:36 -06:00
$this -> load -> model ( 'logbook_model' );
2016-01-09 23:50:42 +00:00
2013-02-22 18:30:33 -06:00
if ( $this -> input -> post ( 'lotwimport' ) == 'fetch' )
2016-01-09 23:50:42 +00:00
{
2013-02-22 18:30:33 -06:00
$file = $config [ 'upload_path' ] . 'lotwreport_download.adi' ;
2016-01-09 23:50:42 +00:00
2013-02-22 18:57:44 -06:00
// Get credentials for LoTW
$query = $this -> user_model -> get_by_id ( $this -> session -> userdata ( 'user_id' ));
2020-04-25 23:11:13 +02:00
$q = $query -> row ();
2020-09-06 17:33:15 +01:00
$data [ 'user_lotw_name' ] = urlencode ( $q -> user_lotw_name );
$data [ 'user_lotw_password' ] = urlencode ( $q -> user_lotw_password );
2016-01-09 23:50:42 +00:00
2013-03-02 14:24:16 -06:00
// Get URL for downloading LoTW
$query = $query = $this -> db -> query ( 'SELECT lotw_download_url FROM config' );
$q = $query -> row ();
$lotw_url = $q -> lotw_download_url ;
2016-01-09 23:50:42 +00:00
2013-02-23 13:25:36 -06:00
// Validate that LoTW credentials are not empty
// TODO: We don't actually see the error message
if ( $data [ 'user_lotw_name' ] == '' || $data [ 'user_lotw_password' ] == '' )
{
2013-03-06 23:33:39 -06:00
$this -> session -> set_flashdata ( 'warning' , 'You have not defined your ARRL LoTW credentials!' ); redirect ( 'lotw/import' );
2013-02-23 13:25:36 -06:00
}
2016-01-09 23:50:42 +00:00
2020-04-25 23:11:13 +02:00
$customDate = $this -> input -> post ( 'from' );
if ( $customDate != NULL ) {
$lotw_last_qsl_date = date ( $customDate );
}
else {
// Query the logbook to determine when the last LoTW confirmation was
2023-07-12 15:56:12 +00:00
$lotw_last_qsl_date = date ( 'Y-m-d' , strtotime ( $this -> logbook_model -> lotw_last_qsl_date ( $this -> session -> userdata [ 'user_id' ])));
2020-04-25 23:11:13 +02:00
}
2016-01-09 23:50:42 +00:00
2013-02-22 18:57:44 -06:00
// Build URL for LoTW report file
2013-03-02 14:24:16 -06:00
$lotw_url .= " ? " ;
2013-02-22 18:57:44 -06:00
$lotw_url .= " login= " . $data [ 'user_lotw_name' ];
$lotw_url .= " &password= " . $data [ 'user_lotw_password' ];
2019-05-22 14:57:20 +01:00
$lotw_url .= " &qso_query=1&qso_qsl='yes'&qso_qsldetail='yes'&qso_mydetail='yes' " ;
2016-01-09 23:50:42 +00:00
2022-05-09 14:44:32 +02:00
$lotw_url .= " &qso_qslsince= " ;
$lotw_url .= " $lotw_last_qsl_date " ;
2016-01-09 23:50:42 +00:00
2023-11-24 16:15:01 +01:00
if ( $this -> input -> post ( 'callsign' ) != '0' ) {
$lotw_url .= " &qso_owncall= " . $this -> input -> post ( 'callsign' );
}
2016-01-09 23:50:42 +00:00
2023-12-10 22:27:20 +01:00
if ( is_writable ( dirname ( $file )) && ( ! file_exists ( $file ) || is_writable ( $file ))) {
file_put_contents ( $file , file_get_contents ( $lotw_url ));
ini_set ( 'memory_limit' , '-1' );
$this -> loadFromFile ( $file );
} else {
if ( ! is_writable ( dirname ( $file ))) {
$data [ 'errormsg' ] = 'Directory ' . dirname ( $file ) . ' is not writable!' ;
} else if ( ! is_writable ( $file )) {
$data [ 'errormsg' ] = 'File ' . $file . ' is not writable!' ;
}
$this -> load -> model ( 'Stations' );
$data [ 'callsigns' ] = $this -> Stations -> callsigns_of_user ( $this -> session -> userdata ( 'user_id' ));
2016-01-09 23:50:42 +00:00
2023-12-10 22:27:20 +01:00
$this -> load -> view ( 'interface_assets/header' , $data );
$this -> load -> view ( 'lotw/import' , $data );
$this -> load -> view ( 'interface_assets/footer' );
}
2013-02-16 16:41:40 +00:00
}
else
{
2013-02-22 18:30:33 -06:00
if ( ! $this -> upload -> do_upload ())
2013-02-21 20:19:58 -06:00
{
2016-01-09 23:50:42 +00:00
2013-02-22 18:30:33 -06:00
$data [ 'error' ] = $this -> upload -> display_errors ();
2023-11-24 16:15:01 +01:00
$this -> load -> model ( 'Stations' );
$data [ 'callsigns' ] = $this -> Stations -> callsigns_of_user ( $this -> session -> userdata ( 'user_id' ));
2013-02-22 18:30:33 -06:00
2019-01-14 16:29:06 +00:00
$this -> load -> view ( 'interface_assets/header' , $data );
2023-11-24 16:15:01 +01:00
$this -> load -> view ( 'lotw/import' , $data );
2019-01-14 16:29:06 +00:00
$this -> load -> view ( 'interface_assets/footer' );
2013-02-21 20:19:58 -06:00
}
else
2013-02-16 16:41:40 +00:00
{
2013-02-21 20:13:42 -06:00
$data = array ( 'upload_data' => $this -> upload -> data ());
2016-01-09 23:50:42 +00:00
2013-02-23 18:40:06 -06:00
$this -> loadFromFile ( './uploads/' . $data [ 'upload_data' ][ 'file_name' ]);
2013-02-21 20:13:42 -06:00
}
2013-02-16 16:41:40 +00:00
}
2013-02-22 18:30:33 -06:00
} // end function
2016-01-09 23:50:42 +00:00
public function export () {
2020-07-01 00:34:51 -06:00
$this -> load -> model ( 'user_model' );
if ( ! $this -> user_model -> authorize ( 2 )) { $this -> session -> set_flashdata ( 'notice' , 'You\'re not allowed to do that!' ); redirect ( 'dashboard' ); }
2020-08-13 17:24:07 +01:00
$data [ 'page_title' ] = " LoTW .TQ8 Upload " ;
2013-03-04 22:59:33 -06:00
$config [ 'upload_path' ] = './uploads/' ;
$config [ 'allowed_types' ] = 'tq8|TQ8' ;
$this -> load -> library ( 'upload' , $config );
if ( ! $this -> upload -> do_upload ())
{
$data [ 'error' ] = $this -> upload -> display_errors ();
2019-01-14 16:29:06 +00:00
$this -> load -> view ( 'interface_assets/header' , $data );
2013-03-04 22:59:33 -06:00
$this -> load -> view ( 'lotw/export' );
2019-01-14 16:29:06 +00:00
$this -> load -> view ( 'interface_assets/footer' );
2013-03-04 22:59:33 -06:00
}
else
2016-01-09 23:50:42 +00:00
{
2013-03-04 22:59:33 -06:00
$data = array ( 'upload_data' => $this -> upload -> data ());
2016-01-09 23:50:42 +00:00
2013-03-05 19:19:52 -06:00
// Figure out how we should be marking QSLs confirmed via LoTW
$query = $query = $this -> db -> query ( 'SELECT lotw_login_url FROM config' );
$q = $query -> row ();
$config [ 'lotw_login_url' ] = $q -> lotw_login_url ;
2016-01-09 23:50:42 +00:00
2013-03-06 23:33:39 -06:00
// Set some fields that we're going to need for ARRL login
2013-03-05 19:19:52 -06:00
$query = $this -> user_model -> get_by_id ( $this -> session -> userdata ( 'user_id' ));
$q = $query -> row ();
2013-03-06 23:33:39 -06:00
$fields [ 'login' ] = $q -> user_lotw_name ;
$fields [ 'password' ] = $q -> user_lotw_password ;
$fields [ 'acct_sel' ] = " " ;
2016-01-09 23:50:42 +00:00
2013-03-06 23:33:39 -06:00
if ( $fields [ 'login' ] == '' || $fields [ 'password' ] == '' )
{
$this -> session -> set_flashdata ( 'warning' , 'You have not defined your ARRL LoTW credentials!' ); redirect ( 'lotw/status' );
}
2016-01-09 23:50:42 +00:00
2013-03-04 22:59:33 -06:00
// Curl stuff goes here
2016-01-09 23:50:42 +00:00
2013-03-05 19:19:52 -06:00
// First we need to get a cookie
// options
$cookie_file_path = " ./uploads/cookies.txt " ;
$agent = " Mozilla/4.0 (compatible;) " ;
// begin script
2016-01-09 23:50:42 +00:00
$ch = curl_init ();
2013-03-05 19:19:52 -06:00
// extra headers
$headers [] = " Accept: */* " ;
$headers [] = " Connection: Keep-Alive " ;
// basic curl options for all requests
curl_setopt ( $ch , CURLOPT_HTTPHEADER , $headers );
curl_setopt ( $ch , CURLOPT_HEADER , 0 );
2016-01-09 23:50:42 +00:00
2013-03-05 19:19:52 -06:00
// TODO: These SSL things should probably be set to true :)
curl_setopt ( $ch , CURLOPT_SSL_VERIFYHOST , 0 );
2016-01-09 23:50:42 +00:00
curl_setopt ( $ch , CURLOPT_SSL_VERIFYPEER , false );
curl_setopt ( $ch , CURLOPT_USERAGENT , $agent );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , 1 );
curl_setopt ( $ch , CURLOPT_FOLLOWLOCATION , 1 );
curl_setopt ( $ch , CURLOPT_COOKIEFILE , $cookie_file_path );
curl_setopt ( $ch , CURLOPT_COOKIEJAR , $cookie_file_path );
2013-03-05 19:19:52 -06:00
// Set login URL
2013-03-06 23:33:39 -06:00
curl_setopt ( $ch , CURLOPT_URL , $config [ 'lotw_login_url' ]);
2016-01-09 23:50:42 +00:00
2013-03-05 19:19:52 -06:00
// set postfields using what we extracted from the form
2016-01-09 23:50:42 +00:00
$POSTFIELDS = http_build_query ( $fields );
2013-03-05 19:19:52 -06:00
// set post options
2016-01-09 23:50:42 +00:00
curl_setopt ( $ch , CURLOPT_POST , 1 );
curl_setopt ( $ch , CURLOPT_POSTFIELDS , $POSTFIELDS );
2013-03-05 19:19:52 -06:00
// perform login
2016-01-09 23:50:42 +00:00
$result = curl_exec ( $ch );
2013-03-06 23:33:39 -06:00
if ( stristr ( $result , " Username/password incorrect " ))
{
$this -> session -> set_flashdata ( 'warning' , 'Your ARRL username and/or password is incorrect.' ); redirect ( 'lotw/status' );
}
2016-01-09 23:50:42 +00:00
2013-03-05 19:19:52 -06:00
// Now we need to use that cookie and upload the file
// change URL to upload destination URL
curl_setopt ( $ch , CURLOPT_URL , $config [ 'lotw_login_url' ]);
2016-01-09 23:50:42 +00:00
2013-03-05 19:19:52 -06:00
// Grab the file
$postfile = array (
" upfile " => " @./uploads/ " . $data [ 'upload_data' ][ 'file_name' ],
);
2016-01-09 23:50:42 +00:00
2013-03-05 19:19:52 -06:00
//Upload it
2016-01-09 23:50:42 +00:00
curl_setopt ( $ch , CURLOPT_POSTFIELDS , $postfile );
2013-03-05 19:19:52 -06:00
$response = curl_exec ( $ch );
2013-03-06 23:33:39 -06:00
if ( stristr ( $response , " accepted " ))
{
$this -> session -> set_flashdata ( 'lotw_status' , 'accepted' );
$data [ 'page_title' ] = " LoTW .TQ8 Sent " ;
2016-01-09 23:50:42 +00:00
}
2013-03-06 23:33:39 -06:00
elseif ( stristr ( $response , " rejected " ))
{
$this -> session -> set_flashdata ( 'lotw_status' , 'rejected' );
$data [ 'page_title' ] = " LoTW .TQ8 Sent " ;
}
else
{
// If we're here, we didn't find what we're looking for in the ARRL response
// and LoTW is probably down or broken.
$this -> session -> set_flashdata ( 'warning' , 'Did not receive proper response from LoTW. Try again later.' );
$data [ 'page_title' ] = " LoTW .TQ8 Not Sent " ;
}
2016-01-09 23:50:42 +00:00
2013-03-05 19:19:52 -06:00
// Now we need to clean up
unlink ( $cookie_file_path );
unlink ( './uploads/' . $data [ 'upload_data' ][ 'file_name' ]);
2016-01-09 23:50:42 +00:00
2019-01-14 16:29:06 +00:00
$this -> load -> view ( 'interface_assets/header' , $data );
2013-03-06 23:33:39 -06:00
$this -> load -> view ( 'lotw/status' );
2019-01-14 16:29:06 +00:00
$this -> load -> view ( 'interface_assets/footer' );
2016-01-09 23:50:42 +00:00
}
2013-03-04 22:59:33 -06:00
}
2016-01-09 23:50:42 +00:00
2019-06-16 14:31:23 +01:00
/*
2023-07-27 09:16:55 +02:00
Load the ARRL LoTW User Activity CSV and saves into uploads / lotw_users . csv
2021-05-01 19:52:13 +02:00
*/
2020-09-21 14:02:50 +01:00
public function load_users () {
$contents = file_get_contents ( 'https://lotw.arrl.org/lotw-user-activity.csv' , true );
2021-05-01 19:52:13 +02:00
if ( $contents === FALSE ) {
2023-02-08 17:32:08 +01:00
echo " Something went wrong with fetching the LoTW users file. " ;
2020-09-21 14:02:50 +01:00
} else {
$file = './updates/lotw_users.csv' ;
2023-02-08 17:32:08 +01:00
if ( file_put_contents ( $file , $contents ) !== FALSE ) { // Save our content to the file.
echo " LoTW User Data Saved. " ;
} else {
echo " FAILED: Could not write to LoTW users file " ;
2020-09-21 14:02:50 +01:00
}
}
2019-06-16 14:31:23 +01:00
}
/*
2023-07-27 09:16:55 +02:00
Check if callsign is an active LoTW user and return whether its true or not
2019-06-16 14:31:23 +01:00
*/
function lotw_usercheck ( $callsign ) {
2020-09-21 14:02:50 +01:00
$f = fopen ( './updates/lotw_users.csv' , " r " );
2020-09-21 17:45:12 +01:00
$result = false ;
while ( $row = fgetcsv ( $f )) {
if ( $row [ 0 ] == strtoupper ( $callsign )) {
$result = $row [ 0 ];
echo " Found " ;
break ;
} else {
echo " Not Found " ;
break ;
}
}
fclose ( $f );
2019-06-16 14:31:23 +01:00
}
2020-08-25 17:50:52 +01:00
function signlog ( $sign_key , $string ) {
2020-08-12 23:53:24 +01:00
2020-08-25 17:50:52 +01:00
$qso_string = $string ;
2020-08-12 23:53:24 +01:00
2020-08-25 17:50:52 +01:00
$key = $sign_key ;
2020-08-12 23:53:24 +01:00
2020-08-25 17:50:52 +01:00
$pkeyid = openssl_pkey_get_private ( $key , 'cloudlog' );
2020-08-13 23:03:25 +01:00
//openssl_sign($plaintext, $signature, $pkeyid, OPENSSL_ALGO_SHA1 );
//openssl_free_key($pkeyid);
2020-08-12 23:53:24 +01:00
2020-08-13 23:03:25 +01:00
if ( openssl_sign ( $qso_string , $signature , $pkeyid , OPENSSL_ALGO_SHA1 )) {
2023-01-02 16:15:56 +01:00
if ( defined ( 'PHP_MAJOR_VERSION' ) && PHP_MAJOR_VERSION < 8 ) {
openssl_free_key ( $pkeyid );
}
2020-08-13 23:03:25 +01:00
$signature_b64 = base64_encode ( $signature );
2024-05-13 16:38:30 +02:00
return $signature_b64 . " \n " ;
2020-08-13 23:03:25 +01:00
}
2020-08-12 23:53:24 +01:00
}
2020-09-03 23:20:22 +01:00
/*
| Function : lotw_satellite_map
| Requires : OSCAR Satellite name $satname
|
2023-07-27 09:16:55 +02:00
| Outputs if LoTW uses a different satellite name
2020-09-03 23:20:22 +01:00
|
*/
function lotw_satellite_map ( $satname ) {
$arr = array (
" ARISS " => " ISS " ,
" UKUBE1 " => " UKUBE-1 " ,
" KEDR " => " ARISSAT-1 " ,
" TO-108 " => " CAS-6 " ,
" TAURUS " => " TAURUS-1 " ,
2020-09-05 22:03:30 +01:00
" AISAT1 " => " AISAT-1 " ,
2021-11-04 11:39:51 +00:00
'UVSQ' => " UVSQ-SAT " ,
'CAS-3H' => " LILACSAT-2 " ,
2022-11-16 13:48:40 +00:00
'IO-117' => " GREENCUBE " ,
2023-05-15 21:37:55 -03:00
" TEVEL1 " => " TEVEL-1 " ,
" TEVEL2 " => " TEVEL-2 " ,
" TEVEL3 " => " TEVEL-3 " ,
" TEVEL4 " => " TEVEL-4 " ,
" TEVEL5 " => " TEVEL-5 " ,
" TEVEL6 " => " TEVEL-6 " ,
" TEVEL7 " => " TEVEL-7 " ,
" TEVEL8 " => " TEVEL-8 " ,
2023-11-01 15:57:25 +00:00
" INSPR7 " => " INSPIRE-SAT 7 " ,
2024-10-24 13:45:15 +01:00
" SONATE " => " SONATE-2 " ,
2024-12-07 10:59:40 +00:00
'AO-123' => " ASRTU-1 " ,
2026-05-16 11:45:03 +01:00
'TEV2-1' => " TEVEL2-1 " ,
'TEV2-2' => " TEVEL2-2 " ,
2025-07-30 10:26:16 +01:00
'TEV2-3' => " TEVEL2-3 " ,
2026-05-16 11:45:03 +01:00
'TEV2-4' => " TEVEL2-4 " ,
'TEV2-5' => " TEVEL2-5 " ,
'TEV2-6' => " TEVEL2-6 " ,
'TEV2-7' => " TEVEL2-7 " ,
'TEV2-8' => " TEVEL2-8 " ,
'TEV2-9' => " TEVEL2-9 " ,
2020-09-03 23:20:22 +01:00
);
return array_search ( strtoupper ( $satname ), $arr , true );
}
2021-05-01 19:52:13 +02:00
2022-03-15 18:04:24 +00:00
/*
| Function : lotw_ca_province_map
| Requires : candian province map $ca_province
2022-03-15 13:14:03 +00:00
*/
function lotw_ca_province_map ( $ca_prov ) {
switch ( $ca_prov ) :
case " QC " :
return " PQ " ;
break ;
2024-05-14 18:10:43 +01:00
case " NL " :
return " NF " ;
break ;
2022-03-15 13:14:03 +00:00
default :
return $ca_prov ;
endswitch ;
}
2021-03-18 17:06:21 +00:00
/*
| Function : mode_map
2021-03-19 15:55:58 -07:00
| Requires : mode as $mode , submode as $submode
2021-03-18 17:06:21 +00:00
|
| This converts ADIF modes to the mode that LoTW expects if its non standard
*/
2021-03-19 15:55:58 -07:00
function mode_map ( $mode , $submode ) {
2021-03-18 17:06:21 +00:00
switch ( $mode ) :
case " PKT " :
2021-03-18 17:08:01 +00:00
return " PACKET " ;
2021-03-18 17:06:21 +00:00
break ;
2021-03-19 15:55:58 -07:00
case " MFSK " :
if ( $submode == " FT4 " ) {
return " FT4 " ;
break ;
2021-11-04 11:43:17 +00:00
} elseif ( $submode == " FST4 " ) {
2021-11-20 20:51:01 +08:00
return " FST4 " ;
break ;
} elseif ( $submode == " MFSK16 " ) {
return " MFSK16 " ;
break ;
} elseif ( $submode == " MFSK8 " ) {
return " MFSK8 " ;
break ;
2021-11-04 11:43:17 +00:00
} elseif ( $submode == " Q65 " ) {
2021-11-20 20:51:01 +08:00
return " Q65 " ;
break ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
} elseif ( $submode == " FSQCALL " ) {
return " DATA " ;
break ;
} elseif ( $submode == " JS8 " ) {
return " DATA " ;
break ;
} elseif ( $submode == " MFSK11 " ) {
return " DATA " ;
break ;
} elseif ( $submode == " MFSK128 " ) {
return " DATA " ;
break ;
} elseif ( $submode == " MFSK22 " ) {
return " DATA " ;
break ;
} elseif ( $submode == " MFSK31 " ) {
return " DATA " ;
break ;
} elseif ( $submode == " MFSK32 " ) {
return " DATA " ;
break ;
} elseif ( $submode == " MFSK4 " ) {
return " DATA " ;
break ;
} elseif ( $submode == " MFSK64 " ) {
return " DATA " ;
break ;
2021-03-19 15:55:58 -07:00
} else {
2021-11-20 20:51:01 +08:00
return " DATA " ;
2021-03-19 15:55:58 -07:00
break ;
}
2022-01-04 17:10:32 +00:00
case " PSK " :
if ( $submode == " PSK31 " ) {
return " PSK31 " ;
break ;
} elseif ( $submode == " PSK63 " ) {
2022-01-05 22:17:45 +00:00
return " PSK63 " ;
break ;
} elseif ( $submode == " BPSK125 " ) {
return " PSK125 " ;
break ;
} elseif ( $submode == " BPSK31 " ) {
return " PSK31 " ;
break ;
} elseif ( $submode == " BPSK63 " ) {
return " PSK63 " ;
break ;
} elseif ( $submode == " FSK31 " ) {
return " FSK31 " ;
break ;
} elseif ( $submode == " PSK10 " ) {
return " PSK10 " ;
break ;
} elseif ( $submode == " PSK125 " ) {
return " PSK125 " ;
break ;
} elseif ( $submode == " PSK500 " ) {
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
return " DATA " ;
2022-01-05 22:17:45 +00:00
break ;
} elseif ( $submode == " PSK63F " ) {
return " PSK63F " ;
break ;
} elseif ( $submode == " PSKAM10 " ) {
return " PSKAM " ;
break ;
} elseif ( $submode == " PSKAM31 " ) {
return " PSKAM " ;
break ;
} elseif ( $submode == " PSKAM50 " ) {
return " PSKAM " ;
break ;
} elseif ( $submode == " PSKFEC31 " ) {
return " PSKFEC31 " ;
break ;
} elseif ( $submode == " QPSK125 " ) {
return " PSK125 " ;
break ;
} elseif ( $submode == " QPSK31 " ) {
return " PSK31 " ;
break ;
} elseif ( $submode == " QPSK63 " ) {
return " PSK63 " ;
break ;
} elseif ( $submode == " PSK2K " ) {
return " PSK2K " ;
break ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
} elseif ( $submode == " PSK1000 " ) {
return " DATA " ;
break ;
} elseif ( $submode == " PSK250 " ) {
return " DATA " ;
break ;
} elseif ( $submode == " QPSK250 " ) {
return " DATA " ;
break ;
} elseif ( $submode == " QPSK500 " ) {
return " DATA " ;
break ;
} elseif ( $submode == " SIM31 " ) {
return " DATA " ;
break ;
2022-01-04 17:10:32 +00:00
} else {
return " DATA " ;
break ;
}
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
case " JT65 " :
if ( $submode == " JT65A " ) {
2025-08-02 13:04:39 +01:00
return " JT65 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT65B " ) {
2025-08-02 13:04:39 +01:00
return " JT65 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT65B2 " ) {
2025-08-02 13:04:39 +01:00
return " JT65 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT65C " ) {
2025-08-02 13:04:39 +01:00
return " JT65 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT65C2 " ) {
2025-08-02 13:04:39 +01:00
return " JT65 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " JT65 " ;
break ;
}
case " JT4 " :
if ( $submode == " JT4A " ) {
2025-08-02 13:04:39 +01:00
return " JT4 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT4B " ) {
2025-08-02 13:04:39 +01:00
return " JT4 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT4C " ) {
2025-08-02 13:04:39 +01:00
return " JT4 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT4D " ) {
2025-08-02 13:04:39 +01:00
return " JT4 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT4E " ) {
2025-08-02 13:04:39 +01:00
return " JT4 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT4F " ) {
2025-08-02 13:04:39 +01:00
return " JT4 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT4G " ) {
2025-08-02 13:04:39 +01:00
return " JT4 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " JT4 " ;
break ;
}
case " JT9 " :
if ( $submode == " JT9-1 " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9-10 " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9-2 " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9-30 " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9-5 " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9A " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9B " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9C " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9D " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9E " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9E FAST " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9F " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9F FAST " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9G " ) {
return " JT9G " ;
break ;
} elseif ( $submode == " JT9G FAST " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9H " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " JT9H FAST " ) {
2025-08-02 13:04:39 +01:00
return " JT9 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " JT9 " ;
break ;
}
case " QRA64 " :
if ( $submode == " QRA64A " ) {
2025-08-02 13:04:39 +01:00
return " QRA64 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " QRA64B " ) {
2025-08-02 13:04:39 +01:00
return " QRA64 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " QRA64C " ) {
2025-08-02 13:04:39 +01:00
return " QRA64 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " QRA64D " ) {
2025-08-02 13:04:39 +01:00
return " QRA64 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " QRA64E " ) {
2025-08-02 13:04:39 +01:00
return " QRA64 " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " QRA64 " ;
break ;
}
case " ISCAT " :
if ( $submode == " ISCAT-A " ) {
2025-08-02 13:04:39 +01:00
return " ISCAT " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " ISCAT-B " ) {
2025-08-02 13:04:39 +01:00
return " ISCAT " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " ISCAT " ;
break ;
}
case " OLIVIA " :
if ( $submode == " OLIVIA 16/1000 " ) {
2025-08-02 13:04:39 +01:00
return " OLIVIA " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " OLIVIA 16/500 " ) {
2025-08-02 13:04:39 +01:00
return " OLIVIA " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " OLIVIA 32/1000 " ) {
2025-08-02 13:04:39 +01:00
return " OLIVIA " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " OLIVIA 4/125 " ) {
2025-08-02 13:04:39 +01:00
return " OLIVIA " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " OLIVIA 4/250 " ) {
2025-08-02 13:04:39 +01:00
return " OLIVIA " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " OLIVIA 8/250 " ) {
2025-08-02 13:04:39 +01:00
return " OLIVIA " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " OLIVIA 8/500 " ) {
2025-08-02 13:04:39 +01:00
return " OLIVIA " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " OLIVIA " ;
break ;
}
case " OPERA " :
if ( $submode == " OPERA-BEACON " ) {
2025-08-02 13:04:39 +01:00
return " OPERA " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " OPERA-QSO " ) {
2025-08-02 13:04:39 +01:00
return " OPERA " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " OPERA " ;
break ;
}
case " ROS " :
if ( $submode == " ROS-EME " ) {
2025-08-02 13:04:39 +01:00
return " ROS " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " ROS-HF " ) {
2025-08-02 13:04:39 +01:00
return " ROS " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " ROS-MF " ) {
2025-08-02 13:04:39 +01:00
return " ROS " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " ROS " ;
break ;
}
case " HELL " :
if ( $submode == " FMHELL " ) {
2025-08-02 13:04:39 +01:00
return " HELL " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " FSKHELL " ) {
2025-08-02 13:04:39 +01:00
return " HELL " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " HELL80 " ) {
2025-08-02 13:04:39 +01:00
return " HELL " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " HFSK " ) {
return " HFSK " ;
break ;
} elseif ( $submode == " PSKHELL " ) {
2025-08-02 13:04:39 +01:00
return " HELL " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " HELL " ;
break ;
}
case " DOMINO " :
if ( $submode == " DOMINOEX " ) {
2025-08-02 13:04:39 +01:00
return " DOMINO " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " DOMINOF " ) {
2025-08-02 13:04:39 +01:00
return " DOMINO " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " DOMINO " ;
break ;
}
case " CHIP " :
if ( $submode == " CHIP128 " ) {
2025-08-02 13:04:39 +01:00
return " CHIP " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " CHIP64 " ) {
2025-08-02 13:04:39 +01:00
return " CHIP " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " CHIP " ;
break ;
}
case " PAC " :
if ( $submode == " PAC2 " ) {
return " PACTOR " ;
break ;
} elseif ( $submode == " PAC3 " ) {
return " PACTOR " ;
break ;
} elseif ( $submode == " PAC4 " ) {
return " PACTOR " ;
break ;
} else {
return " PACTOR " ;
break ;
}
case " PAX " :
if ( $submode == " PAX2 " ) {
2025-08-02 13:04:39 +01:00
return " PAX " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " PAX " ;
break ;
}
case " TOR " :
if ( $submode == " AMTORFEC " ) {
return " AMTOR " ;
break ;
} elseif ( $submode == " GTOR " ) {
return " GTOR " ;
break ;
} else {
return " AMTOR " ;
break ;
}
case " THRB " :
if ( $submode == " THRBX " ) {
return " THROB " ;
break ;
} else {
return " THROB " ;
break ;
}
case " SSB " :
if ( $submode == " LSB " ) {
2025-08-02 11:53:23 +01:00
return " SSB " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} elseif ( $submode == " USB " ) {
2025-08-02 11:53:23 +01:00
return " SSB " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " SSB " ;
break ;
}
case " RTTY " :
if ( $submode == " ASCI " ) {
2025-08-02 12:01:38 +01:00
return " RTTY " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " RTTY " ;
break ;
}
case " CW " :
if ( $submode == " PCW " ) {
2025-08-02 12:01:38 +01:00
return " CW " ;
Expand mode and submode mapping in Lotw controller
Added comprehensive handling for various digital modes and submodes in the Lotw controller, including detailed mappings for JT65, JT4, JT9, QRA64, ISCAT, OLIVIA, OPERA, ROS, HELL, DOMINO, CHIP, PAC, PAX, TOR, THRB, SSB, RTTY, CW, CLO, and V4. This improves the accuracy of mode translation and ensures better compatibility with a wider range of digital communication formats.
2025-07-29 16:01:57 +01:00
break ;
} else {
return " CW " ;
break ;
}
case " CLO " :
return " CLOVER " ;
break ;
case " V4 " :
return " DATA " ;
break ;
2021-03-18 17:06:21 +00:00
default :
2021-03-18 17:08:01 +00:00
return $mode ;
2021-03-18 17:06:21 +00:00
endswitch ;
}
2016-01-09 23:50:42 +00:00
} // end class