From 505ad499ac24968c32e02764013e7d87e29250ef Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Mon, 18 Nov 2024 08:19:07 +0000 Subject: [PATCH 01/19] start cbr parser --- application/libraries/Cbr_parser.php | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 application/libraries/Cbr_parser.php diff --git a/application/libraries/Cbr_parser.php b/application/libraries/Cbr_parser.php new file mode 100755 index 000000000..a843df658 --- /dev/null +++ b/application/libraries/Cbr_parser.php @@ -0,0 +1,6 @@ + From 525f430ea9dcdb439678aeb42bb6d1fe92daa415 Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Mon, 18 Nov 2024 13:27:29 +0000 Subject: [PATCH 02/19] initial implementation --- application/controllers/Cabrillo.php | 157 +++++++++++ application/libraries/Cbr_parser.php | 298 +++++++++++++++++++++ application/models/Logbook_model.php | 61 +++++ application/views/adif/import.php | 38 +++ application/views/cabrillo/cbr_success.php | 45 ++++ 5 files changed, 599 insertions(+) create mode 100755 application/views/cabrillo/cbr_success.php diff --git a/application/controllers/Cabrillo.php b/application/controllers/Cabrillo.php index d713b2e9b..faeb2a869 100644 --- a/application/controllers/Cabrillo.php +++ b/application/controllers/Cabrillo.php @@ -139,4 +139,161 @@ class Cabrillo extends CI_Controller { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } } + + public function cbrimport(){ + + //load user stations + $this->load->model('stations'); + $data['station_profile'] = $this->stations->all_of_user(); + + //set page title and target tab + $data['page_title'] = __("Cabrillo Import"); + $data['tab'] = "cbr"; + + //configure upload + $config['upload_path'] = './uploads/'; + $config['allowed_types'] = 'cbr|CBR'; + + //load upload library + $this->load->library('upload', $config); + + //if upload fails, return with errors, reset upload filesize + if ( ! $this->upload->do_upload()) { + $data['error'] = $this->upload->display_errors(); + + $data['max_upload'] = ini_get('upload_max_filesize'); + + $this->load->view('interface_assets/header', $data); + $this->load->view('adif/import', $data); + $this->load->view('interface_assets/footer'); + return; + } + + //get data from upload + $data = array('upload_data' => $this->upload->data()); + + //set memory limit to allow big files + ini_set('memory_limit', '-1'); + set_time_limit(0); + + //load the logbook model + $this->load->model('logbook_model'); + + //load the Cabrillo parser + if (!$this->load->is_loaded('cbr_parser')) { + $this->load->library('cbr_parser'); + } + + //parse the uploaded file + $parsed_cbr = $this->cbr_parser->parse_from_file('./uploads/'.$data['upload_data']['file_name']); + + //return with error, reset upload filesize + if(count($parsed_cbr["QSOS"]) < 1) + { + $data['error'] = __("Broken CBR file - no QSO data or incomplete header found."); + + $data['max_upload'] = ini_get('upload_max_filesize'); + + $this->load->view('interface_assets/header', $data); + $this->load->view('adif/import', $data); + $this->load->view('interface_assets/footer'); + return; + } + + //get flag about the presence of the serial number + $serial_number_present = ($this->input('serial_number_present', true) == 1); + + //get all station ids for the active user + $this->load->model('stations'); + $station_ids = []; + foreach ($this->stations->all_of_user() as $station) { + array_push($station_ids, $station->station_id); + } + + //create helper variables + $custom_errors = []; + $i = 1; + + //process each contest qso + foreach ($parsed_cbr["QSOS"] as $qso) { + + //get relevant data from header and qso line + $station_callsign = $parsed_cbr["HEADER"]["CALLSIGN"]; + $contest_id = $parsed_cbr["HEADER"]["CONTEST"]; + $callsign = $qso["RCVD_CALLSIGN"]; + $band = $qso["BAND"]; + $mode = $qso["MODE"]; + $date = $qso["DATE"]; + $time = $qso["TIME"]; + + //load QSO + $contest_qsos = $this->logbook_model->getContestQSO($station_ids, $station_callsign, $contest_id, $callsign, $band, $mode, $date, $time)->result(); + + //create error if more than 1 QSO is found and skip + if(count($contest_qsos) != 1){ + array_push($custom_errors, "QSO " . $i . " not found or more that 1 QSOs found that match the criteria of the CBR file. Skipping as a safety measure."); + $i++; + continue; + } + + //load the first and only row + $contest_qso = $contest_qsos[0]; + + //load unique primary key + $contest_qso_id = $contest_qso->COL_PRIMARY_KEY; + + //get new serial numbers if required, otherwise default to null. If serial is not numeric, use 0 + $stx = $serial_number_present ? (is_numeric($qso["SENT_SERIAL"]) ? (int)$qso["SENT_SERIAL"] : 0) : null; + $srx = $serial_number_present ? (is_numeric($qso["RCVD_SERIAL"]) ? (int)$qso["RCVD_SERIAL"] : 0) : null; + + //get count of exchanges + $sent_exchange_count = $parsed_cbr["SENT_EXCHANGE_COUNT"]; + $rcvd_exchange_count = $parsed_cbr["RCVD_EXCHANGE_COUNT"]; + + //default to empty exchange strings + $stxstring = null; + $srxstring = null; + + //process all sent exchanges + for ($i=1; $i <= $sent_exchange_count; $i++) { + if($stxstring == null) + { + $stxstring = $qso["SENT_EXCH_" . $i]; + }else{ + $stxstring += ' ' . $qso["SENT_EXCH_" . $i]; + } + } + + //process all sent exchanges + for ($i=1; $i <= $rcvd_exchange_count; $i++) { + if($srxstring == null) + { + $srxstring = $qso["RCVD_EXCH_" . $i]; + }else{ + $srxstring += ' ' . $qso["RCVD_EXCH_" . $i]; + } + } + + //correct data on contest qso + $this->logbook_model->set_contest_fields($contest_qso_id, $stx, $stxstring, $srx, $srxstring); + + //increment counter + $i++; + + } + + //delete uploaded file + unlink('./uploads/' . $data['upload_data']['file_name']); + + //set data for view + $data['cbr_errors'] = $custom_errors; + $data['cbr_error_count'] = count($custom_errors); + $data['cbr_update_count'] = count($parsed_cbr["QSOS"]) - count($custom_errors); + $data['page_title'] = __("CBR Data Imported"); + + //get view to user + $this->load->view('interface_assets/header', $data); + $this->load->view('cabrillo/cbr_success'); + $this->load->view('interface_assets/footer'); + } } diff --git a/application/libraries/Cbr_parser.php b/application/libraries/Cbr_parser.php index a843df658..ce56b06a8 100755 --- a/application/libraries/Cbr_parser.php +++ b/application/libraries/Cbr_parser.php @@ -1,6 +1,304 @@ parse(mb_convert_encoding(file_get_contents($filename), "UTF-8")); + } + public function parse(string $input, $serial_number_present = false) : array + { + //split the input into lines + $lines = explode("\n", trim($input)); + + //initialize the result array + $qso_lines_raw = []; + $header = []; + + //helper variable to determine common 59 element indices in QSO lines + $common_59_indices = null; + + //flag to indicate processing mode + $qso_mode = false; + + //helper variable to determine the maximum number of qso data fields + $max_qso_fields = 0; + + //loop through each line + foreach ($lines as $line) { + + //if we encounter "QSO" or "X-QSO" switch processing mode to QSO mode + if (strpos($line, 'QSO:') === 0 or strpos($line, 'X-QSO:') === 0) { + $qso_mode = true; + }else { + $qso_mode = false; + } + + //if we encounter "END-OF-LOG", stop processing lines + if (strpos($line, 'END-OF-LOG') === 0) { + break; + } + + //process and collect header lines if qso mode is not set + if (!$qso_mode) { + + //split the line into an array using ': ' as the delimiter + $parts = explode(': ', $line, 2); + + //collect header information + $header[$parts[0]] = $parts[1]; + + //skip to next line + continue; + } + + //process and collect QSO lines if qso mode is set + if ($qso_mode) { + + //split the line into the elements + $qso_elements = preg_split('/\s+/', trim($line)); + + //determine maximum qso field size + $max_qso_fields = max($max_qso_fields, count($qso_elements)); + + //add qso elements to qso line array + array_push($qso_lines_raw, $qso_elements); + + //find all occurrences of "59" + $indices_of_59 = []; + foreach ($qso_elements as $index => $value) { + if ($value === "59" or $value === "599") { + $indices_of_59[] = $index; + } + } + + //find common indices position + if ($common_59_indices === null) { + //initialize common indices on the first iteration + $common_59_indices = $indices_of_59; + } else { + //intersect with current indices, preserving only common indices + $common_59_indices = array_intersect($common_59_indices, $indices_of_59); + } + + //skip to next line + continue; + } + } + + //abort further processing if no qso lines were found, return header only + if(count($qso_lines_raw) < 1) + { + $result = []; + $result["HEADER"] = $header; + $result["QSOS"] = []; + $result["SENT_59_POS"] = 0; + $result["RCVD_59_POS"] = 0; + $result["SENT_EXCHANGE_COUNT"] = 0; + $result["RCVD_EXCHANGE_COUNT"] = 0; + + //return result + return $result; + } + + //abort if basic things (Callsign and Contest ID) are not included in the header + $header_fields = array_keys($header); + if(!in_array('CALLSIGN', $header_fields) or !in_array('CONTEST', $header)){ + $result = []; + $result["HEADER"] = $header; + $result["QSOS"] = []; + $result["SENT_59_POS"] = 0; + $result["RCVD_59_POS"] = 0; + $result["SENT_EXCHANGE_COUNT"] = 0; + $result["RCVD_EXCHANGE_COUNT"] = 0; + + //return blank result + return $result; + } + + //get positions of 59s inside QSO lines + $sent_59_pos = min($common_59_indices); + $rcvd_59_pos = max($common_59_indices); + + //get codeigniter instance + $CI = &get_instance(); + + //load Frequency library + if(!$CI->load->is_loaded('Frequency')) { + $CI->load->library('Frequency'); + } + + //using 59 positions, remake qso_lines + $qso_lines = []; + + //change all QSOs into associative arrays with meaningful keys + foreach ($qso_lines_raw as $line) { + + $qso_line = []; + + //get well defined fields + $qso_line["QSO_MARKER"] = $line[0]; + $qso_line["FREQ"] = $line[1]; + $qso_line["CBR_MODE"] = $line[2]; + $qso_line["DATE"] = $line[3]; + $qso_line["TIME"] = $line[4]; + $qso_line["OWN_CALLSIGN"] = $line[5]; + $qso_line["SENT_59"] = $line[$sent_59_pos]; + + //set serial if requested + if($serial_number_present) + { + $qso_line["SENT_SERIAL"] = $line[$sent_59_pos + 1]; + } + + //get all remaining sent exchanges + $exchange_nr = 1; + $startindex = ($sent_59_pos + ($serial_number_present ? 2 : 1)); + $endindex = ($rcvd_59_pos - 1); + for ($i = $startindex; $i < $endindex; $i++) { + $qso_line["SENT_EXCH_" . $exchange_nr] = $line[$i]; + $exchange_nr++; + } + + //get rest of the well defined fields + $qso_line["RCVD_CALLSIGN"] = $line[$rcvd_59_pos - 1]; + $qso_line["RCVD_59"] = $line[$rcvd_59_pos]; + + //set serial if requested + if($serial_number_present) + { + $qso_line["RCVD_SERIAL"] = $line[$rcvd_59_pos + 1]; + } + + //get all remaining received exchanges + $exchange_nr = 1; + $startindex = ($rcvd_59_pos + ($serial_number_present ? 2 : 1)); + $endindex = (count($line)); + for ($i = $startindex; $i < $endindex; $i++) { + $qso_line["RCVD_EXCH_" . $exchange_nr] = $line[$i]; + $exchange_nr++; + } + + //end of data in CQR format + //enhance QSO data with additional fields + $band = ""; + + //convert frequency to integer if possible + if(is_numeric($qso_line["FREQ"])) { + $frequency = (int)$qso_line["FREQ"]; + }else{ + $frequency = null; + } + + //convert CBR values to band where no real frequency is given. + //if frequency is given, consult the frequency library + switch ($qso_line["FREQ"]) { + case '50': + $band = '6m'; + break; + case '70': + $band = '4m'; + break; + case '144': + $band = '2m'; + break; + case '222': + $band = '1.25m'; + break; + case '432': + $band = '70cm'; + break; + case '902': + $band = '33cm'; + break; + case '1.2G': + $band = '23cm'; + break; + case '2.3G': + $band = '13cm'; + break; + case '3.4G': + $band = '9cm'; + break; + case '5.7G': + $band = '6cm'; + break; + case '10G': + $band = '3cm'; + break; + case '24G': + $band = '1.25cm'; + break; + case '47G': + $band = 'SAT'; + break; + case '75G': + $band = 'SAT'; + break; + case '122G': + $band = 'SAT'; + break; + case '134G': + $band = 'SAT'; + break; + case '241G': + $band = 'SAT'; + break; + case 'LIGHT': + $band = 'SAT'; + break; + default: + $band = $CI->frequency->GetBand($frequency * 1000); + break; + } + + //set band data for QSO + $qso_line["BAND"] = $band; + + //get Wavelog mode + $mode = ""; + switch ($qso_line["CBR_MODE"]) { + case 'CW': + $mode = 'CW'; + break; + case 'PH': + $mode = 'SSB'; + break; + case 'FM': + $mode = 'FM'; + break; + case 'RY': + $mode = 'RTTY'; + break; + case 'DG': + //indeterminate Digimode + $mode = ''; + break; + default: + //something is wrong with the CBR file + $mode = ''; + break; + } + + //set mode data for QSO + $qso_line["MODE"] = $mode; + + //collect new associative array + array_push($qso_lines, $qso_line); + } + + //construct result, including positions of 59s for further processing down the line + $result = []; + $result["HEADER"] = $header; + $result["QSOS"] = $qso_lines; + $result["SENT_59_POS"] = $sent_59_pos; + $result["RCVD_59_POS"] = $rcvd_59_pos; + $result["SENT_EXCHANGE_COUNT"] = $rcvd_59_pos - $sent_59_pos - ($serial_number_present ? 3 : 2); + $result["RCVD_EXCHANGE_COUNT"] = $max_qso_fields - 1 - $rcvd_59_pos - ($serial_number_present ? 1 : 0); + + //return result + return $result; + } } ?> diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index a9e24387e..1448660b1 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -5427,9 +5427,70 @@ class Logbook_model extends CI_Model { } return ''; } + + function getContestQSO(array $station_ids, string $station_callsign, string $contest_id, string $callsign, string $band, string $mode, string $date, string $time) + { + + //load QSO table + $this->db->select('*'); + $this->db->from($this->config->item('table_name')); + + //load only for given station_ids + $this->db->where_in('station_id', $station_ids); + + //load only for the station_callsign given + $this->db->where('COL_STATION_CALLSIGN', xss_clean($station_callsign)); + + //load only for the given contest id + $this->db->where('COL_CONTEST_ID', xss_clean($contest_id)); + + //load only for this qso partners callsign + $this->db->where('COL_CALL', xss_clean($callsign)); + + //load only for given band (no cleaning necessary because provided by wavelog itself) + $this->db->where('COL_BAND', $band); + + //load only for specific mode if the mode is determinate. If not, omit it. In most cases, that should be fine. Also provided by wavelog itself, so no cleaning. + if($mode != '') + { + $this->db->where('COL_MODE', $mode); + } + + //prepare datetime from format '2099-12-31 13:47' to be usable in a performant query + $datetime_raw = $date . ' ' . substr($time, 0, 2) . ':' . substr($time, 2, 2); + $datetime = new DateTime($datetime_raw,new DateTimeZone('UTC')); + $synthetic_endtime = $datetime->add(new DateInterval('PT1M')); + + //load only for specific date and time. Since + $this->db->where('COL_TIME_ON >=', $datetime->format('Y-m-d H:i:s')); + $this->db->where('COL_TIME_ON <', $synthetic_endtime->format('Y-m-d H:i:s')); + + //return whatever is left + return $this->db->get(); + } + + function set_contest_fields($qso_primary_key, ?int $stx, ?string $stxstring, ?int $srx, ?string $srxstring) { + + //assemble data fields from input + $data = $data = array( + 'COL_STX' => $stx, + 'COL_STX_STRING' => $stxstring == null ? null : substr($stxstring, 0, 32), + 'COL_SRX' => $srx, + 'COL_SRX_STRING' => $srxstring == null ? null : substr($srxstring, 0, 32) + ); + + //narrow db operation down to 1 QSO + $this->db->where(array('COL_PRIMARY_KEY' => $qso_primary_key)); + + //update data and return + $this->db->update($this->config->item('table_name'), $data); + return; + } + } function validateADIFDate($date, $format = 'Ymd') { $d = DateTime::createFromFormat($format, $date); return $d && $d->format($format) == $date; } + diff --git a/application/views/adif/import.php b/application/views/adif/import.php index 0415314b7..c44df4357 100644 --- a/application/views/adif/import.php +++ b/application/views/adif/import.php @@ -35,6 +35,15 @@ echo 'false'; } ?>"> + @@ -285,6 +294,35 @@ +
+ + + + +

Information

+

Important

+
+ +
+
+
+ + +
+
+
+
+ + +
+
+ diff --git a/application/views/cabrillo/cbr_success.php b/application/views/cabrillo/cbr_success.php new file mode 100755 index 000000000..3fcc68881 --- /dev/null +++ b/application/views/cabrillo/cbr_success.php @@ -0,0 +1,45 @@ +
+
+ session->flashdata('message')) { ?> + +
+

session->flashdata('message'); ?>

+
+ + +
+
+ +
+
+ 0) { ?> +

Yay, its updated!

+

+ +

+ + + +

+

+ + + + + + + + + + + + +
+ +
+
+ + +
From 0b2ea8c6bc6dd948ce704983128f409749be52cc Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Mon, 18 Nov 2024 13:37:10 +0000 Subject: [PATCH 03/19] added success page --- application/views/cabrillo/cbr_success.php | 27 ++++++++-------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/application/views/cabrillo/cbr_success.php b/application/views/cabrillo/cbr_success.php index 3fcc68881..f38626dac 100755 --- a/application/views/cabrillo/cbr_success.php +++ b/application/views/cabrillo/cbr_success.php @@ -12,32 +12,25 @@
- 0) { ?> + 0) { ?>

Yay, its updated!

-

+

- -

-

+ 0) { ?> +

- - - - - - - - - + + + + -
- +
From eccf8ac57617281f0b179ace82f726bd2e976a27 Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Mon, 18 Nov 2024 14:43:08 +0000 Subject: [PATCH 04/19] bug fixes --- application/controllers/Cabrillo.php | 16 ++++++++-------- application/libraries/Cbr_parser.php | 8 ++++---- application/models/Logbook_model.php | 12 +++++++----- application/views/adif/import.php | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/application/controllers/Cabrillo.php b/application/controllers/Cabrillo.php index faeb2a869..ff6f43c13 100644 --- a/application/controllers/Cabrillo.php +++ b/application/controllers/Cabrillo.php @@ -9,8 +9,8 @@ if ( ! defined('BASEPATH')) exit('No direct script access allowed'); class Cabrillo extends CI_Controller { - function __construct() { - parent::__construct(); + public function __construct() { + parent::__construct(); $this->load->model('user_model'); if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } @@ -152,7 +152,7 @@ class Cabrillo extends CI_Controller { //configure upload $config['upload_path'] = './uploads/'; - $config['allowed_types'] = 'cbr|CBR'; + $config['allowed_types'] = 'cbr|CBR|log|LOG'; //load upload library $this->load->library('upload', $config); @@ -184,8 +184,11 @@ class Cabrillo extends CI_Controller { $this->load->library('cbr_parser'); } + //get flag about the presence of the serial number + $serial_number_present = ($this->input->post('serial_number_present', true) == 1); + //parse the uploaded file - $parsed_cbr = $this->cbr_parser->parse_from_file('./uploads/'.$data['upload_data']['file_name']); + $parsed_cbr = $this->cbr_parser->parse_from_file('./uploads/'.$data['upload_data']['file_name'], $serial_number_present); //return with error, reset upload filesize if(count($parsed_cbr["QSOS"]) < 1) @@ -200,13 +203,10 @@ class Cabrillo extends CI_Controller { return; } - //get flag about the presence of the serial number - $serial_number_present = ($this->input('serial_number_present', true) == 1); - //get all station ids for the active user $this->load->model('stations'); $station_ids = []; - foreach ($this->stations->all_of_user() as $station) { + foreach ($this->stations->all_of_user()->result() as $station) { array_push($station_ids, $station->station_id); } diff --git a/application/libraries/Cbr_parser.php b/application/libraries/Cbr_parser.php index ce56b06a8..e4f2e4d73 100755 --- a/application/libraries/Cbr_parser.php +++ b/application/libraries/Cbr_parser.php @@ -1,10 +1,10 @@ parse(mb_convert_encoding(file_get_contents($filename), "UTF-8")); + return $this->parse(mb_convert_encoding(file_get_contents($filename), "UTF-8"), $serial_number_present); } public function parse(string $input, $serial_number_present = false) : array @@ -47,7 +47,7 @@ class CBR_Parser $parts = explode(': ', $line, 2); //collect header information - $header[$parts[0]] = $parts[1]; + $header[$parts[0]] = preg_replace('/\s+/', '', $parts[1]); //skip to next line continue; @@ -104,7 +104,7 @@ class CBR_Parser //abort if basic things (Callsign and Contest ID) are not included in the header $header_fields = array_keys($header); - if(!in_array('CALLSIGN', $header_fields) or !in_array('CONTEST', $header)){ + if(!in_array('CALLSIGN', $header_fields) or !in_array('CONTEST', $header_fields)){ $result = []; $result["HEADER"] = $header; $result["QSOS"] = []; diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index 1448660b1..7987b1448 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -5459,11 +5459,13 @@ class Logbook_model extends CI_Model { //prepare datetime from format '2099-12-31 13:47' to be usable in a performant query $datetime_raw = $date . ' ' . substr($time, 0, 2) . ':' . substr($time, 2, 2); $datetime = new DateTime($datetime_raw,new DateTimeZone('UTC')); - $synthetic_endtime = $datetime->add(new DateInterval('PT1M')); - - //load only for specific date and time. Since - $this->db->where('COL_TIME_ON >=', $datetime->format('Y-m-d H:i:s')); - $this->db->where('COL_TIME_ON <', $synthetic_endtime->format('Y-m-d H:i:s')); + $from_datetime = $datetime->format('Y-m-d H:i:s'); + $datetime->add(new DateInterval('PT1M')); + $to_datetime = $datetime->format('Y-m-d H:i:s'); + + //load only QSOs during this minute + $this->db->where('COL_TIME_ON >=', $from_datetime); + $this->db->where('COL_TIME_ON <', $to_datetime); //return whatever is left return $this->db->get(); diff --git a/application/views/adif/import.php b/application/views/adif/import.php index c44df4357..6cf40fc87 100644 --- a/application/views/adif/import.php +++ b/application/views/adif/import.php @@ -312,7 +312,7 @@
- +
From 9a7edd8374265832b5a400065bb5c2309dffdcf1 Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Mon, 18 Nov 2024 14:49:54 +0000 Subject: [PATCH 05/19] fix operand --- application/controllers/Cabrillo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/controllers/Cabrillo.php b/application/controllers/Cabrillo.php index ff6f43c13..17ca2121e 100644 --- a/application/controllers/Cabrillo.php +++ b/application/controllers/Cabrillo.php @@ -260,7 +260,7 @@ class Cabrillo extends CI_Controller { { $stxstring = $qso["SENT_EXCH_" . $i]; }else{ - $stxstring += ' ' . $qso["SENT_EXCH_" . $i]; + $stxstring = $stxstring . ' ' . $qso["SENT_EXCH_" . $i]; } } @@ -270,7 +270,7 @@ class Cabrillo extends CI_Controller { { $srxstring = $qso["RCVD_EXCH_" . $i]; }else{ - $srxstring += ' ' . $qso["RCVD_EXCH_" . $i]; + $srxstring = $srxstring . ' ' . $qso["RCVD_EXCH_" . $i]; } } From 15b0a7aae5b531cd8fed197c04526fa4b0eab4c8 Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Mon, 18 Nov 2024 14:52:56 +0000 Subject: [PATCH 06/19] fix error formatting --- application/views/cabrillo/cbr_success.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/views/cabrillo/cbr_success.php b/application/views/cabrillo/cbr_success.php index f38626dac..80138eee9 100755 --- a/application/views/cabrillo/cbr_success.php +++ b/application/views/cabrillo/cbr_success.php @@ -24,11 +24,11 @@ 0) { ?>

- + - +
From 3b2ceb7ee5de9d7c413b266a69aa876b7fa9391b Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Tue, 19 Nov 2024 06:30:11 +0000 Subject: [PATCH 07/19] fix curly braces and commit suggested changes by HB9HIL --- application/controllers/Cabrillo.php | 2 +- application/libraries/Cbr_parser.php | 9 +++------ application/models/Logbook_model.php | 3 +-- application/views/adif/dcl_success.php | 2 +- application/views/adif/import.php | 4 ++-- application/views/cabrillo/cbr_success.php | 2 +- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/application/controllers/Cabrillo.php b/application/controllers/Cabrillo.php index 17ca2121e..49265a1e1 100644 --- a/application/controllers/Cabrillo.php +++ b/application/controllers/Cabrillo.php @@ -231,7 +231,7 @@ class Cabrillo extends CI_Controller { //create error if more than 1 QSO is found and skip if(count($contest_qsos) != 1){ - array_push($custom_errors, "QSO " . $i . " not found or more that 1 QSOs found that match the criteria of the CBR file. Skipping as a safety measure."); + array_push($custom_errors, sprintf(__("QSO %s not found or more that 1 QSOs found that match the criteria of the CBR file. Skipping as a safety measure.", $i))); $i++; continue; } diff --git a/application/libraries/Cbr_parser.php b/application/libraries/Cbr_parser.php index e4f2e4d73..7995444b8 100755 --- a/application/libraries/Cbr_parser.php +++ b/application/libraries/Cbr_parser.php @@ -88,8 +88,7 @@ class CBR_Parser } //abort further processing if no qso lines were found, return header only - if(count($qso_lines_raw) < 1) - { + if(count($qso_lines_raw) < 1) { $result = []; $result["HEADER"] = $header; $result["QSOS"] = []; @@ -147,8 +146,7 @@ class CBR_Parser $qso_line["SENT_59"] = $line[$sent_59_pos]; //set serial if requested - if($serial_number_present) - { + if($serial_number_present) { $qso_line["SENT_SERIAL"] = $line[$sent_59_pos + 1]; } @@ -166,8 +164,7 @@ class CBR_Parser $qso_line["RCVD_59"] = $line[$rcvd_59_pos]; //set serial if requested - if($serial_number_present) - { + if($serial_number_present) { $qso_line["RCVD_SERIAL"] = $line[$rcvd_59_pos + 1]; } diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index 7987b1448..20043e446 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -5451,8 +5451,7 @@ class Logbook_model extends CI_Model { $this->db->where('COL_BAND', $band); //load only for specific mode if the mode is determinate. If not, omit it. In most cases, that should be fine. Also provided by wavelog itself, so no cleaning. - if($mode != '') - { + if($mode != '') { $this->db->where('COL_MODE', $mode); } diff --git a/application/views/adif/dcl_success.php b/application/views/adif/dcl_success.php index 9763a9eed..321de6ad9 100644 --- a/application/views/adif/dcl_success.php +++ b/application/views/adif/dcl_success.php @@ -13,7 +13,7 @@
0) { ?> -

Yay, its updated!

+

diff --git a/application/views/adif/import.php b/application/views/adif/import.php index 6cf40fc87..f0e94ce1d 100644 --- a/application/views/adif/import.php +++ b/application/views/adif/import.php @@ -305,8 +305,8 @@
-

Information

-

Important

+

+

diff --git a/application/views/cabrillo/cbr_success.php b/application/views/cabrillo/cbr_success.php index 80138eee9..7e11d8119 100755 --- a/application/views/cabrillo/cbr_success.php +++ b/application/views/cabrillo/cbr_success.php @@ -13,7 +13,7 @@
0) { ?> -

Yay, its updated!

+

From 9737f51e2c931fdc37e4069b549e488f6147ef4f Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Tue, 19 Nov 2024 06:46:11 +0000 Subject: [PATCH 08/19] better describe serial number switch in UI --- application/views/adif/import.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/views/adif/import.php b/application/views/adif/import.php index f0e94ce1d..368b36b23 100644 --- a/application/views/adif/import.php +++ b/application/views/adif/import.php @@ -313,8 +313,9 @@
- +
+
From 6bfcf39d76a700b10dc8627f87a0dbd591d47676 Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Tue, 19 Nov 2024 06:56:28 +0000 Subject: [PATCH 09/19] delete upload file if parsing fails --- application/controllers/Cabrillo.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/application/controllers/Cabrillo.php b/application/controllers/Cabrillo.php index 49265a1e1..7342bd181 100644 --- a/application/controllers/Cabrillo.php +++ b/application/controllers/Cabrillo.php @@ -197,6 +197,9 @@ class Cabrillo extends CI_Controller { $data['max_upload'] = ini_get('upload_max_filesize'); + //delete uploaded file + unlink('./uploads/' . $data['upload_data']['file_name']); + $this->load->view('interface_assets/header', $data); $this->load->view('adif/import', $data); $this->load->view('interface_assets/footer'); From 1b8ebfa90c0c7cb4c9ef1c3f2f73aaaa6d709449 Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Tue, 26 Nov 2024 11:01:39 +0000 Subject: [PATCH 10/19] add info about imported contests during adif import --- application/controllers/Adif.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/application/controllers/Adif.php b/application/controllers/Adif.php index 7ead333e8..0d8d93328 100644 --- a/application/controllers/Adif.php +++ b/application/controllers/Adif.php @@ -225,10 +225,24 @@ class adif extends CI_Controller { $this->adif_parser->initialize(); $custom_errors = ""; $alladif=[]; + $contest_qso_infos = []; while($record = $this->adif_parser->get_record()) { + + //overwrite the contest id if user chose a contest in UI if ($contest != '') { - $record['contest_id']=$contest; + $record['contest_id'] = $contest; } + + //check if contest_id exists in record and extract all found contest_ids + if(array_key_exists('contest_id', $record)){ + $contest_id = $record['contest_id']; + if(array_key_exists($contest_id, $contest_qso_infos)){ + $contest_qso_infos[$contest_id] += 1; + }else{ + $contest_qso_infos[$contest_id] = 1; + } + } + if(count($record) == 0) { break; }; @@ -265,6 +279,7 @@ class adif extends CI_Controller { log_message("Error","ADIF End"); $data['adif_errors'] = $custom_errors; $data['skip_dupes'] = $this->input->post('skipDuplicate'); + $data['imported_contests'] = $contest_qso_infos; $data['page_title'] = __("ADIF Imported"); $this->load->view('interface_assets/header', $data); From b8e0ff15501ffe2bddc483477f7a40206ed8288b Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Tue, 26 Nov 2024 11:35:06 +0000 Subject: [PATCH 11/19] fix bug counting contests --- application/controllers/Adif.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/application/controllers/Adif.php b/application/controllers/Adif.php index 0d8d93328..fd2929aa3 100644 --- a/application/controllers/Adif.php +++ b/application/controllers/Adif.php @@ -236,10 +236,12 @@ class adif extends CI_Controller { //check if contest_id exists in record and extract all found contest_ids if(array_key_exists('contest_id', $record)){ $contest_id = $record['contest_id']; - if(array_key_exists($contest_id, $contest_qso_infos)){ - $contest_qso_infos[$contest_id] += 1; - }else{ - $contest_qso_infos[$contest_id] = 1; + if($contest_id != ''){ + if(array_key_exists($contest_id, $contest_qso_infos)){ + $contest_qso_infos[$contest_id] += 1; + }else{ + $contest_qso_infos[$contest_id] = 1; + } } } From b3989b3b2af7529a03fdabee8025b07530ccaa0b Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Wed, 27 Nov 2024 09:18:29 +0000 Subject: [PATCH 12/19] add contest select to cbr import --- application/controllers/Cabrillo.php | 6 ++++++ application/views/adif/import.php | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/application/controllers/Cabrillo.php b/application/controllers/Cabrillo.php index 7342bd181..fb3368bb4 100644 --- a/application/controllers/Cabrillo.php +++ b/application/controllers/Cabrillo.php @@ -170,6 +170,7 @@ class Cabrillo extends CI_Controller { } //get data from upload + $contest_id = $this->input->post('contest_id', false) ?? ''; $data = array('upload_data' => $this->upload->data()); //set memory limit to allow big files @@ -213,6 +214,11 @@ class Cabrillo extends CI_Controller { array_push($station_ids, $station->station_id); } + //overwrite contest id if chosen during upload + if($contest_id != ''){ + $parsed_cbr["HEADER"]["CONTEST"] = $contest_id; + } + //create helper variables $custom_errors = []; $i = 1; diff --git a/application/views/adif/import.php b/application/views/adif/import.php index 368b36b23..dedd9b2fe 100644 --- a/application/views/adif/import.php +++ b/application/views/adif/import.php @@ -311,6 +311,14 @@
+
+
From 25e87868d7d29a62997de271ea6d1018df7a6463 Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Wed, 8 Jan 2025 11:58:16 +0000 Subject: [PATCH 13/19] add display for imported contest data on adif import --- application/controllers/Adif.php | 6 ------ application/views/adif/import_success.php | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/application/controllers/Adif.php b/application/controllers/Adif.php index 932ad83b6..cc7808e43 100644 --- a/application/controllers/Adif.php +++ b/application/controllers/Adif.php @@ -240,7 +240,6 @@ class adif extends CI_Controller { if ($contest != '') { $record['contest_id'] = $contest; } -<<<<<<< HEAD //check if contest_id exists in record and extract all found contest_ids if(array_key_exists('contest_id', $record)){ @@ -254,11 +253,6 @@ class adif extends CI_Controller { } } -======= - if ($club_operator != '') { - $record['operator']=strtoupper($club_operator); - } ->>>>>>> dev if(count($record) == 0) { break; }; diff --git a/application/views/adif/import_success.php b/application/views/adif/import_success.php index c2d36a281..6868cf2d0 100644 --- a/application/views/adif/import_success.php +++ b/application/views/adif/import_success.php @@ -20,6 +20,21 @@ echo " ".__("Dupes were skipped."); } ?>

+ + + 0)?> +

+

+

+ + +
    + $qsocount) { ?> +
  • + +
+ +

From 7c833894b652f8e6b6a395b021fe1a43905d5df6 Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Wed, 8 Jan 2025 11:59:55 +0000 Subject: [PATCH 14/19] fix bug --- application/controllers/Adif.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/application/controllers/Adif.php b/application/controllers/Adif.php index cc7808e43..aaeff629d 100644 --- a/application/controllers/Adif.php +++ b/application/controllers/Adif.php @@ -241,6 +241,10 @@ class adif extends CI_Controller { $record['contest_id'] = $contest; } + //handle club operator + if ($club_operator != '') { + $record['operator']=strtoupper($club_operator); + //check if contest_id exists in record and extract all found contest_ids if(array_key_exists('contest_id', $record)){ $contest_id = $record['contest_id']; From 535caa13884040d015a7d9d136ed3b965aa925d6 Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Wed, 8 Jan 2025 12:02:47 +0000 Subject: [PATCH 15/19] fix bug --- application/controllers/Adif.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/controllers/Adif.php b/application/controllers/Adif.php index aaeff629d..d60268b6f 100644 --- a/application/controllers/Adif.php +++ b/application/controllers/Adif.php @@ -243,7 +243,8 @@ class adif extends CI_Controller { //handle club operator if ($club_operator != '') { - $record['operator']=strtoupper($club_operator); + $record['operator'] = strtoupper($club_operator); + } //check if contest_id exists in record and extract all found contest_ids if(array_key_exists('contest_id', $record)){ From a3874ee7a8f413ab2e419628613123770f1426f3 Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Wed, 8 Jan 2025 12:05:09 +0000 Subject: [PATCH 16/19] formatting --- application/views/adif/import_success.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/application/views/adif/import_success.php b/application/views/adif/import_success.php index 6868cf2d0..cf31c987a 100644 --- a/application/views/adif/import_success.php +++ b/application/views/adif/import_success.php @@ -12,8 +12,12 @@
+ +

+ + " . __("Dupes were inserted!") . ""; } else { From 316b7e66d3fc040b28bb190d0429a4a624a0a96c Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Wed, 8 Jan 2025 12:20:41 +0000 Subject: [PATCH 17/19] fix display when no contests are imported --- application/views/adif/import_success.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/views/adif/import_success.php b/application/views/adif/import_success.php index cf31c987a..4fde24239 100644 --- a/application/views/adif/import_success.php +++ b/application/views/adif/import_success.php @@ -26,7 +26,7 @@

- 0)?> + 0) {?>

@@ -37,6 +37,7 @@
  • + From 464f4dfbc690262172abd18ee97db1436c214f6e Mon Sep 17 00:00:00 2001 From: DB4SCW Date: Wed, 8 Jan 2025 13:24:01 +0000 Subject: [PATCH 18/19] fix error message for contest qsos not found in cbr import --- application/controllers/Cabrillo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/controllers/Cabrillo.php b/application/controllers/Cabrillo.php index faa733964..5b04820e8 100644 --- a/application/controllers/Cabrillo.php +++ b/application/controllers/Cabrillo.php @@ -240,7 +240,7 @@ class Cabrillo extends CI_Controller { //create error if more than 1 QSO is found and skip if(count($contest_qsos) != 1){ - array_push($custom_errors, sprintf(__("QSO %s not found or more that 1 QSOs found that match the criteria of the CBR file. Skipping as a safety measure.", $i))); + array_push($custom_errors, sprintf(__("QSO %d not found or more that 1 QSOs found that match the criteria of the CBR file. Skipping as a safety measure."), $i)); $i++; continue; } From 1e188d12f6cf2c41c2c7fd4652b02e016a7830bd Mon Sep 17 00:00:00 2001 From: phl0 Date: Wed, 22 Jan 2025 11:20:42 +0100 Subject: [PATCH 19/19] Some improvements for CBR parser --- application/config/mimes.php | 4 +++- application/controllers/Cabrillo.php | 2 +- application/libraries/Cbr_parser.php | 28 ++++++++++++++-------------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/application/config/mimes.php b/application/config/mimes.php index c3a1de5aa..989b5c6ce 100644 --- a/application/config/mimes.php +++ b/application/config/mimes.php @@ -185,5 +185,7 @@ return array( 'ADI' => array('application/octet-stream','text/plain', 'audio/x-hx-aac-adif'), 'ADIF' => array('application/octet-stream','text/plain', 'audio/x-hx-aac-adif'), 'tq8' => 'application/octet-stream', - 'TQ8' => 'application/octet-stream' + 'TQ8' => 'application/octet-stream', + 'cbr' => array('application/octet-stream','text/plain'), + 'CBR' => array('application/octet-stream','text/plain') ); diff --git a/application/controllers/Cabrillo.php b/application/controllers/Cabrillo.php index 5b04820e8..972fd0f5e 100644 --- a/application/controllers/Cabrillo.php +++ b/application/controllers/Cabrillo.php @@ -240,7 +240,7 @@ class Cabrillo extends CI_Controller { //create error if more than 1 QSO is found and skip if(count($contest_qsos) != 1){ - array_push($custom_errors, sprintf(__("QSO %d not found or more that 1 QSOs found that match the criteria of the CBR file. Skipping as a safety measure."), $i)); + array_push($custom_errors, sprintf(__("QSO %d not found or more than 1 QSO found that match the criteria of the CBR file. Skipping as a safety measure."), $i)); $i++; continue; } diff --git a/application/libraries/Cbr_parser.php b/application/libraries/Cbr_parser.php index 7995444b8..73c35a0db 100755 --- a/application/libraries/Cbr_parser.php +++ b/application/libraries/Cbr_parser.php @@ -42,12 +42,12 @@ class CBR_Parser //process and collect header lines if qso mode is not set if (!$qso_mode) { - + //split the line into an array using ': ' as the delimiter $parts = explode(': ', $line, 2); //collect header information - $header[$parts[0]] = preg_replace('/\s+/', '', $parts[1]); + $header[$parts[0]] = trim($parts[1]); //skip to next line continue; @@ -55,13 +55,13 @@ class CBR_Parser //process and collect QSO lines if qso mode is set if ($qso_mode) { - + //split the line into the elements $qso_elements = preg_split('/\s+/', trim($line)); //determine maximum qso field size $max_qso_fields = max($max_qso_fields, count($qso_elements)); - + //add qso elements to qso line array array_push($qso_lines_raw, $qso_elements); @@ -81,7 +81,7 @@ class CBR_Parser //intersect with current indices, preserving only common indices $common_59_indices = array_intersect($common_59_indices, $indices_of_59); } - + //skip to next line continue; } @@ -96,7 +96,7 @@ class CBR_Parser $result["RCVD_59_POS"] = 0; $result["SENT_EXCHANGE_COUNT"] = 0; $result["RCVD_EXCHANGE_COUNT"] = 0; - + //return result return $result; } @@ -111,7 +111,7 @@ class CBR_Parser $result["RCVD_59_POS"] = 0; $result["SENT_EXCHANGE_COUNT"] = 0; $result["RCVD_EXCHANGE_COUNT"] = 0; - + //return blank result return $result; } @@ -133,9 +133,9 @@ class CBR_Parser //change all QSOs into associative arrays with meaningful keys foreach ($qso_lines_raw as $line) { - + $qso_line = []; - + //get well defined fields $qso_line["QSO_MARKER"] = $line[0]; $qso_line["FREQ"] = $line[1]; @@ -144,7 +144,7 @@ class CBR_Parser $qso_line["TIME"] = $line[4]; $qso_line["OWN_CALLSIGN"] = $line[5]; $qso_line["SENT_59"] = $line[$sent_59_pos]; - + //set serial if requested if($serial_number_present) { $qso_line["SENT_SERIAL"] = $line[$sent_59_pos + 1]; @@ -154,7 +154,7 @@ class CBR_Parser $exchange_nr = 1; $startindex = ($sent_59_pos + ($serial_number_present ? 2 : 1)); $endindex = ($rcvd_59_pos - 1); - for ($i = $startindex; $i < $endindex; $i++) { + for ($i = $startindex; $i < $endindex; $i++) { $qso_line["SENT_EXCH_" . $exchange_nr] = $line[$i]; $exchange_nr++; } @@ -172,7 +172,7 @@ class CBR_Parser $exchange_nr = 1; $startindex = ($rcvd_59_pos + ($serial_number_present ? 2 : 1)); $endindex = (count($line)); - for ($i = $startindex; $i < $endindex; $i++) { + for ($i = $startindex; $i < $endindex; $i++) { $qso_line["RCVD_EXCH_" . $exchange_nr] = $line[$i]; $exchange_nr++; } @@ -180,7 +180,7 @@ class CBR_Parser //end of data in CQR format //enhance QSO data with additional fields $band = ""; - + //convert frequency to integer if possible if(is_numeric($qso_line["FREQ"])) { $frequency = (int)$qso_line["FREQ"]; @@ -188,7 +188,7 @@ class CBR_Parser $frequency = null; } - //convert CBR values to band where no real frequency is given. + //convert CBR values to band where no real frequency is given. //if frequency is given, consult the frequency library switch ($qso_line["FREQ"]) { case '50':