;;; qso.el --- Amateur radio QSO logging -*- lexical-binding: t; -*-

;; Copyright (C) 2026, David Pentrack
;; Author: David Pentrack
;; URL: https://github.com/K6SM/Emacs-QSO-Logger
;; Keywords: lisp
;; Package-Version: 20260707.1515
;; Package-Revision: a3b0d1f0b103

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

;;; Package-Requires: ((emacs "25.1"))

;;; Commentary:

;; This LISP code provides some basic functions for Emacs to rapidly
;; capture and log amateur radio contacts (QSOs) into an ADIF file.
;;
;; qso.el provides a fuction that generates a customizable, dynamic
;; form (qso-log-form) to log amateur radio QSOs using almost any
;; combination of ADIF fields in the ADIF 3.1.4 specification.
;; This allows the user to customize the form for use in contests or
;; general logging.  All customizations are accessible in the "QSO"
;; group, whose parent is the Emacs "Applications" group, accessed
;; with M-x customize.
;;
;; Further processing of the logs can be done within Emacs or by
;; importing the ADIF file into another logging program.

;; Features

;; - Simple, customizable text interface for real-time ham radio QSO
;;   logging or even to rapidly convert paper log entries to an ADIF
;; - Runs entirely in a Linux terminal environment, allowing for its
;;   use in ultra-light, low-power HW/SW configurations (e.g. terminal-
;;   only mode on a Raspberry Pi Zero 2W)
;; - No mouse required (using tab or shift-tab to change fields or
;;   hover over buttons)
;; - Log entries are appended to a user-specified ADIF log file
;; - Any field in the ADIF 3.1.4 specification can be selected to
;;   appear on the form, in whatever order is desired
;; - Each field has an option to preserve the most recent information
;;   after a QSO submission
;;   - Example: For situations where frequency and mode unchanged
;;     between QSOs
;;   - Also useful for repeating sent information reports in contests
;; - Automatically populates BAND based on FREQ for commonly used
;;   bands, if otherwise left blank or not shown on the form
;; - Option to lookup callsign information and show the information
;;   (text) in another buffer (requires an internet connection)
;; - Option to check the log for duplicates before recording the QSO
;; - Option to clear the form without saving the information (e.g.
;;   for incomplete QSOs)
;;
;; Getting Started
;;
;;  1) Execute M-x customize, select "Applications" and then select
;;     "QSO" to see the customization options.
;;  2) Enter your callsign in the QSO Operator field.
;;  3) Enter the path to the ADIF file you will be using
;;     (e.g. ~/qsolog.adi).
;;  4) Add, remove, or reorder the fields you wish to have on the form.
;;  5) Select or deselect form fields that you wish you have cleared
;;     after a QSO submission (especially helpful for contests).
;;  6) Click "Apply" or "Apply and Save" as appropriate.
;;  7) Execute M-x qso-log-form to bring up and begin using the log
;;     entry form.

;;; Code:

(require 'wid-edit)
(require 'cl-lib)

(defgroup qso nil
  "Amateur radio QSO logging."
  :tag "QSO"
  :group 'applications)

(defcustom qso-adif-path "~/qso-log.adi"
  "Path to QSO ADIF file."
  :tag "QSO ADIF Path"
  :type 'string
  :group 'qso)

(defcustom qso-adif-title "Generated by Emacs QSO Logger"
  "Title of the ADIF file to appear in the first line of the ADIF header."
  :tag "QSO ADIF Title"
  :type 'string
  :group 'qso)

(defcustom qso-call-lookup t
  "If non-nil, provide a callsign lookup function/button."
  :tag "QSO Callsign Lookup"
  :type 'boolean
  :group 'qso)

(defcustom qso-call-lookup-autofill-name nil
  "If non-nil, provide a callsign lookup/autofill-name function/button."
  :tag "QSO Callsign Lookup Autofill Name"
  :type 'boolean
  :group 'qso)

(defcustom qso-call-duplicates t
  "Enable duplicate callsign checking."
  :tag "QSO Call Duplicates"
  :type 'boolean
  :group 'qso)

(defcustom qso-OPERATOR "MYCALL"
  "Control operator's callsign."
  :tag "QSO Operator"
  :type 'string
  :group 'qso)

(defcustom qso-form-fields
  '((CALL . t)
    (NAME . t)
    (RST_RCVD . t)
    (RST_SENT . nil)
    (FREQ . nil)
    (MODE . nil)
    (COMMENT . t))
  "Fields to show in the QSO Log Entry form and which to clear between entries."
  :tag "QSO Form Fields"
  :type '(alist :key-type (choice (const :tag "ADDRESS" ADDRESS)
				  (const :tag "ADDRESS_INTL" ADDRESS_INTL)
				  (const :tag "AGE" AGE)
				  (const :tag "ALTITUDE" ALTITUDE)
				  (const :tag "ANT_AZ" ANT_AZ)
				  (const :tag "ANT_EL" ANT_EL)
				  (const :tag "ANT_PATH" ANT_PATH)
				  (const :tag "ARRL_SECT" ARRL_SECT)
				  (const :tag "AWARD_GRANTED" AWARD_GRANTED)
				  (const :tag "AWARD_SUBMITTED" AWARD_SUBMITTED)
				  (const :tag "A_INDEX" A_INDEX)
				  (const :tag "BAND" BAND)
				  (const :tag "BAND_RX" BAND_RX)
				  (const :tag "CALL" CALL)
				  (const :tag "CHECK" CHECK)
				  (const :tag "CLASS" CLASS)
				  (const :tag "CLUBLOG_QSO_UPLOAD_DATE" CLUBLOG_QSO_UPLOAD_DATE)
				  (const :tag "CLUBLOG_QSO_UPLOAD_STATUS" CLUBLOG_QSO_UPLOAD_STATUS)
				  (const :tag "CNTY" CNTY)
				  (const :tag "COMMENT" COMMENT)
				  (const :tag "COMMENT_INTL" COMMENT_INTL)
				  (const :tag "CONT" CONT)
				  (const :tag "CONTACTED_OP" CONTACTED_OP)
				  (const :tag "CONTEST_ID" CONTEST_ID)
				  (const :tag "COUNTRY" COUNTRY)
				  (const :tag "COUNTRY_INTL" COUNTRY_INTL)
				  (const :tag "CQZ" CQZ)
				  (const :tag "CREDIT_SUBMITTED" CREDIT_SUBMITTED)
				  (const :tag "CREDIT_GRANTED" CREDIT_GRANTED)
				  (const :tag "DARC_DOK" DARC_DOK)
				  (const :tag "DISTANCE" DISTANCE)
				  (const :tag "DXCC" DXCC)
				  (const :tag "EMAIL" EMAIL)
				  (const :tag "EQ_CALL" EQ_CALL)
				  (const :tag "EQSL_QSLRDATE" EQSL_QSLRDATE)
				  (const :tag "EQSL_QSLSDATE" EQSL_QSLSDATE)
				  (const :tag "EQSL_QSL_RCVD" EQSL_QSL_RCVD)
				  (const :tag "EQSL_QSL_SENT" EQSL_QSL_SENT)
				  (const :tag "FISTS" FISTS)
				  (const :tag "FISTS_CC" FISTS_CC)
				  (const :tag "FORCE_INIT" FORCE_INIT)
				  (const :tag "FREQ" FREQ)
				  (const :tag "FREQ_RX" FREQ_RX)
				  (const :tag "GRIDSQUARE" GRIDSQUARE)
				  (const :tag "GRIDSQUARE_EXT" GRIDSQUARE_EXT)
				  (const :tag "GUEST_OP" GUEST_OP)
				  (const :tag "HAMLOGEU_QSO_UPLOAD_DATE" HAMLOGEU_QSO_UPLOAD_DATE)
				  (const :tag "HAMLOGEU_QSO_UPLOAD_STATUS" HAMLOGEU_QSO_UPLOAD_STATUS)
				  (const :tag "HAMQTH_QSO_UPLOAD_DATE" HAMQTH_QSO_UPLOAD_DATE)
				  (const :tag "HAMQTH_QSO_UPLOAD_STATUS" HAMQTH_QSO_UPLOAD_STATUS)
				  (const :tag "HRDLOG_QSO_UPLOAD_DATE" HRDLOG_QSO_UPLOAD_DATE)
				  (const :tag "HRDLOG_QSO_UPLOAD_STATUS" HRDLOG_QSO_UPLOAD_STATUS)
				  (const :tag "IOTA" IOTA)
				  (const :tag "IOTA_ISLAND_ID" IOTA_ISLAND_ID)
				  (const :tag "ITUZ" ITUZ)
				  (const :tag "K_INDEX" K_INDEX)
				  (const :tag "LAT" LAT)
				  (const :tag "LON" LON)
				  (const :tag "LOTW_QSLRDATE" LOTW_QSLRDATE)
				  (const :tag "LOTW_QSLSDATE" LOTW_QSLSDATE)
				  (const :tag "LOTW_QSL_RCVD" LOTW_QSL_RCVD)
				  (const :tag "LOTW_QSL_SENT" LOTW_QSL_SENT)
				  (const :tag "MAX_BURSTS" MAX_BURSTS)
				  (const :tag "MODE" MODE)
				  (const :tag "MS_SHOWER" MS_SHOWER)
				  (const :tag "MY_ALTITUDE" MY_ALTITUDE)
				  (const :tag "MY_ANTENNA" MY_ANTENNA)
				  (const :tag "MY_ARRL_SECT" MY_ARRL_SECT)
				  (const :tag "MY_CITY" MY_CITY)
				  (const :tag "MY_CITY_INTL" MY_CITY_INTL)
				  (const :tag "MY_CNTY" MY_CNTY)
				  (const :tag "MY_COUNTRY" MY_COUNTRY)
				  (const :tag "MY_COUNTRY_INTL" MY_COUNTRY_INTL)
				  (const :tag "MY_CQ_ZONE" MY_CQ_ZONE)
				  (const :tag "MY_DXCC" MY_DXCC)
				  (const :tag "MY_FISTS" MY_FISTS)
				  (const :tag "MY_GRIDSQUARE" MY_GRIDSQUARE)
				  (const :tag "MY_GRIDSQUARE_EXT" MY_GRIDSQUARE_EXT)
				  (const :tag "MY_IOTA" MY_IOTA)
				  (const :tag "MY_IOTA_ISLAND_ID" MY_IOTA_ISLAND_ID)
				  (const :tag "MY_ITU_ZONE" MY_ITU_ZONE)
				  (const :tag "MY_LAT" MY_LAT)
				  (const :tag "MY_LON" MY_LON)
				  (const :tag "MY_NAME" MY_NAME)
				  (const :tag "MY_NAME_INTL" MY_NAME_INTL)
				  (const :tag "MY_POSTAL_CODE" MY_POSTAL_CODE)
				  (const :tag "MY_POSTAL_CODE_INTL" MY_POSTAL_CODE_INTL)
				  (const :tag "MY_POTA_REF" MY_POTA_REF)
				  (const :tag "MY_RIG" MY_RIG)
				  (const :tag "MY_RIG_INTL" MY_RIG_INTL)
				  (const :tag "MY_SIG" MY_SIG)
				  (const :tag "MY_SIG_INTL" MY_SIG_INTL)
				  (const :tag "MY_SIG_INFO" MY_SIG_INFO)
				  (const :tag "MY_SIG_INFO_INTL" MY_SIG_INFO_INTL)
				  (const :tag "MY_SOTA_REF" MY_SOTA_REF)
				  (const :tag "MY_STATE" MY_STATE)
				  (const :tag "MY_STREET" MY_STREET)
				  (const :tag "MY_STREET_INTL" MY_STREET_INTL)
				  (const :tag "MY_USACA_COUNTIES" MY_USACA_COUNTIES)
				  (const :tag "MY_VUCC_GRIDS" MY_VUCC_GRIDS)
				  (const :tag "MY_WWFF_REF" MY_WWFF_REF)
				  (const :tag "NAME" NAME)
				  (const :tag "NAME_INTL" NAME_INTL)
				  (const :tag "NOTES" NOTES)
				  (const :tag "NOTES_INTL" NOTES_INTL)
				  (const :tag "NR_BURSTS" NR_BURSTS)
				  (const :tag "NR_PINGS" NR_PINGS)
;				  (const :tag "OPERATOR" OPERATOR)
				  (const :tag "OWNER_CALLSIGN" OWNER_CALLSIGN)
				  (const :tag "PFX" PFX)
				  (const :tag "POTA_REF" POTA_REF)
				  (const :tag "PRECEDENCE" PRECEDENCE)
				  (const :tag "PROP_MODE" PROP_MODE)
				  (const :tag "PUBLIC_KEY" PUBLIC_KEY)
				  (const :tag "QRZCOM_QSO_UPLOAD_DATE" QRZCOM_QSO_UPLOAD_DATE)
				  (const :tag "QRZCOM_QSO_UPLOAD_STATUS" QRZCOM_QSO_UPLOAD_STATUS)
				  (const :tag "QSLMSG" QSLMSG)
				  (const :tag "QSLMSG_INTL" QSLMSG_INTL)
				  (const :tag "QSLRDATE" QSLRDATE)
				  (const :tag "QSLSDATE" QSLSDATE)
				  (const :tag "QSL_RCVD" QSL_RCVD)
				  (const :tag "QSL_RCVD_VIA" QSL_RCVD_VIA)
				  (const :tag "QSL_SENT" QSL_SENT)
				  (const :tag "QSL_SENT_VIA" QSL_SENT_VIA)
				  (const :tag "QSL_VIA" QSL_VIA)
				  (const :tag "QSO_COMPLETE" QSO_COMPLETE)
				  (const :tag "QSO_DATE" QSO_DATE)
				  (const :tag "QSO_DATE_OFF" QSO_DATE_OFF)
				  (const :tag "QSO_RANDOM" QSO_RANDOM)
				  (const :tag "QTH" QTH)
				  (const :tag "QTH_INTL" QTH_INTL)
				  (const :tag "REGION" REGION)
				  (const :tag "RIG" RIG)
				  (const :tag "RIG_INTL" RIG_INTL)
				  (const :tag "RST_RCVD" RST_RCVD)
				  (const :tag "RST_SENT" RST_SENT)
				  (const :tag "RX_PWR" RX_PWR)
				  (const :tag "SAT_MODE" SAT_MODE)
				  (const :tag "SAT_NAME" SAT_NAME)
				  (const :tag "SFI" SFI)
				  (const :tag "SIG" SIG)
				  (const :tag "SIG_INTL" SIG_INTL)
				  (const :tag "SIG_INFO" SIG_INFO)
				  (const :tag "SIG_INFO_INTL" SIG_INFO_INTL)
				  (const :tag "SILENT_KEY" SILENT_KEY)
				  (const :tag "SKCC" SKCC)
				  (const :tag "SOTA_REF" SOTA_REF)
				  (const :tag "SRX" SRX)
				  (const :tag "SRX_STRING" SRX_STRING)
				  (const :tag "STATE" STATE)
				  (const :tag "STATION_CALLSIGN" STATION_CALLSIGN)
				  (const :tag "STX" STX)
				  (const :tag "STX_STRING" STX_STRING)
				  (const :tag "SUBMODE" SUBMODE)
				  (const :tag "SWL" SWL)
				  (const :tag "TEN_TEN" TEN_TEN)
				  (const :tag "TIME_OFF" TIME_OFF)
				  (const :tag "TIME_ON" TIME_ON)
				  (const :tag "TX_PWR" TX_PWR)
				  (const :tag "UKSMG" UKSMG)
				  (const :tag "USACA_COUNTIES" USACA_COUNTIES)
				  (const :tag "VE_PROV" VE_PROV)
				  (const :tag "VUCC_GRIDS" VUCC_GRIDS)
				  (const :tag "WEB" WEB)
				  (const :tag "WWFF_REF" WWFF_REF)
                                  (const :tag "Custom Choice" custom-choice))
                :value-type (boolean :tag "Clear after submission"))
  :group 'qso)

(defvar qso-form-field-definitions
  '((ADDRESS . (editable-field :format "ADDRESS: %v\n" :size 40 :value ""))
    (ADDRESS_INTL . (editable-field :format "ADDRESS_INTL: %v\n" :size 40 :value ""))
    (AGE . (editable-field :format "AGE: %v\n" :size 3 :value ""))
    (ALTITUDE . (editable-field :format "ALTITUDE: %vm\n" :size 4 :value ""))
    (ANT_AZ . (editable-field :format "ANT_AZ: %v\n" :size 3 :value ""))
    (ANT_EL . (editable-field :format "ANT_EL: %v\n" :size 3 :value ""))
    (ANT_PATH . (menu-choice :tag "ANT_PATH" :format "ANT_PATH: %[%v%]" :value ""
			 (item :tag "Short Path" :value "S")
			 (item :tag "Grayline" :value "G")
			 (item :tag "Long Path" :value "L")
			 (item :tag "Other" :value "O")))
    (ARRL_SECT . (editable-field :format "ARRL_SECT: %v\n" :size 3 :value ""))
    (AWARD_GRANTED . (editable-field :format "AWARD_GRANTED: %v\n" :size 40 :value ""))
    (AWARD_SUBMITTED . (editable-field :format "AWARD_SUBMITTED: %v\n" :size 40 :value ""))
    (A_INDEX . (editable-field :format "A_INDEX: %v\n" :size 3 :value ""))
    (BAND . (menu-choice :tag "BAND" :format "BAND: %[%v%]" :value ""
			 (item :tag "2190m" :value "2190m")
			 (item :tag "630m" :value "630m")
			 (item :tag "560m" :value "560m")
			 (item :tag "160m" :value "160m")
			 (item :tag "80m" :value "80m")
			 (item :tag "60m" :value "60m")
			 (item :tag "40m" :value "40m")
			 (item :tag "30m" :value "30m")
			 (item :tag "20m" :value "20m")
			 (item :tag "17m" :value "17m")
			 (item :tag "15m" :value "15m")
			 (item :tag "12m" :value "12m")
			 (item :tag "10m" :value "10m")
			 (item :tag "8m" :value "8m")
			 (item :tag "6m" :value "6m")
			 (item :tag "5m" :value "5m")
			 (item :tag "4m" :value "4m")
			 (item :tag "2m" :value "2m")
			 (item :tag "1.25m" :value "1.25m")
			 (item :tag "70cm" :value "70cm")
			 (item :tag "33cm" :value "33cm")
			 (item :tag "23cm" :value "23cm")
			 (item :tag "13cm" :value "13cm")
			 (item :tag "9cm" :value "9cm")
			 (item :tag "6cm" :value "6cm")
			 (item :tag "3cm" :value "3cm")
			 (item :tag "1.25cm" :value "1.25cm")
			 (item :tag "6mm" :value "6mm")
			 (item :tag "4mm" :value "4mm")
			 (item :tag "2.5mm" :value "2.5mm")
			 (item :tag "2mm" :value "2mm")
			 (item :tag "1mm" :value "1mm")
			 (item :tag "submm" :value "submm")))
    (BAND_RX . (editable-field :format "BAND_RX: %v\n" :size 40 :value ""))
    (CALL . (editable-field :format "CALL: %v " :size 10 :value ""))
    (CHECK . (editable-field :format "CHECK: %v\n" :size 40 :value ""))
    (CLASS . (editable-field :format "CLASS: %v\n" :size 10 :value ""))
    (CLUBLOG_QSO_UPLOAD_DATE . (editable-field :format "CLUBLOG_QSO_UPLOAD_DATE: %v\n" :size 40 :value ""))
    (CLUBLOG_QSO_UPLOAD_STATUS . (editable-field :format "CLUBLOG_QSO_UPLOAD_STATUS: %v\n" :size 40 :value ""))
    (CNTY . (editable-field :format "CNTY: %v\n" :size 40 :value ""))
    (COMMENT . (editable-field :format "COMMENT: %v\n" :size 37 :value ""))
    (COMMENT_INTL . (editable-field :format "COMMENT_INTL: %v\n" :size 32 :value ""))
    (CONT . (editable-field :format "CONT: %v\n" :size 2 :value ""))
    (CONTACTED_OP . (editable-field :format "CONTACTED_OP: %v\n" :size 32 :value ""))
    (CONTEST_ID . (menu-choice :tag "CONTEST_ID" :format "CONTEST_ID: %[%v%]" :value ""
			       (item :tag "PODXS Great Pumpkin Sprint" :value "070-160M-SPRINT")
			       (item :tag "PODXS Three Day Weekend" :value "070-3-DAY")
			       (item :tag "PODXS 31 Flavors" :value "070-31-FLAVORS")
			       (item :tag "PODXS 40m Firecracker Sprint" :value "070-40M-SPRINT")
			       (item :tag "PODXS 80m Jay Hudak Memorial Sprint" :value "070-80M-SPRINT")
			       (item :tag "PODXS PSKFest" :value "070-PSKFEST")
			       (item :tag "PODXS St. Patricks Day" :value "070-ST-PATS-DAY")
			       (item :tag "PODXS Valentine Sprint" :value "070-VALENTINE-SPRINT")
			       (item :tag "Ten-Meter RTTY Contest (2011 onwards)" :value "10-RTTY")
			       (item :tag "Open Season Ten Meter QSO Party" :value "1010-OPEN-SEASON")
			       (item :tag "7th-Area QSO Party" :value "7QP")
			       (item :tag "Alabama QSO Party" :value "AL-QSO-PARTY")
			       (item :tag "JARL All Asian DX Contest (CW)" :value "ALL-ASIAN-DX-CW")
			       (item :tag "JARL All Asian DX Contest (PHONE)" :value "ALL-ASIAN-DX-PHONE")
			       (item :tag "ANARTS WW RTTY" :value "ANARTS-RTTY")
			       (item :tag "Anatolian WW RTTY" :value "ANATOLIAN-RTTY")
			       (item :tag "Asia - Pacific Sprint" :value "AP-SPRINT")
			       (item :tag "Arkansas QSO Party" :value "AR-QSO-PARTY")
			       (item :tag "ARI DX Contest" :value "ARI-DX")
			       (item :tag "ARRL 10 Meter Contest" :value "ARRL-10")
			       (item :tag "ARRL 10 GHz and Up Contest" :value "ARRL-10-GHZ")
			       (item :tag "ARRL 160 Meter Contest" :value "ARRL-160")
			       (item :tag "ARRL 222 MHz and Up Distance Contest" :value "ARRL-222")
			       (item :tag "ARRL International Digital Contest" :value "ARRL-DIGI")
			       (item :tag "ARRL International DX Contest (CW)" :value "ARRL-DX-CW")
			       (item :tag "ARRL International DX Contest (Phone)" :value "ARRL-DX-SSB")
			       (item :tag "ARRL EME contest" :value "ARRL-EME")
			       (item :tag "ARRL Field Day" :value "ARRL-FIELD-DAY")
			       (item :tag "ARRL Rookie Roundup (CW)" :value "ARRL-RR-CW")
			       (item :tag "ARRL Rookie Roundup (RTTY)" :value "ARRL-RR-RTTY")
			       (item :tag "ARRL Rookie Roundup (Phone)" :value "ARRL-RR-SSB")
			       (item :tag "ARRL RTTY Round-Up" :value "ARRL-RTTY")
			       (item :tag "ARRL School Club Roundup" :value "ARRL-SCR")
			       (item :tag "ARRL November Sweepstakes (CW)" :value "ARRL-SS-CW")
			       (item :tag "ARRL November Sweepstakes (Phone)" :value "ARRL-SS-SSB")
			       (item :tag "ARRL August UHF Contest" :value "ARRL-UHF-AUG")
			       (item :tag "ARRL January VHF Sweepstakes" :value "ARRL-VHF-JAN")
			       (item :tag "ARRL June VHF QSO Party" :value "ARRL-VHF-JUN")
			       (item :tag "ARRL September VHF QSO Party" :value "ARRL-VHF-SEP")
			       (item :tag "Arizona QSO Party" :value "AZ-QSO-PARTY")
			       (item :tag "BARTG Spring RTTY Contest" :value "BARTG-RTTY")
			       (item :tag "BARTG Sprint Contest" :value "BARTG-SPRINT")
			       (item :tag "British Columbia QSO Party" :value "BC-QSO-PARTY")
			       (item :tag "California QSO Party" :value "CA-QSO-PARTY")
			       (item :tag "CIS DX Contest" :value "CIS-DX")
			       (item :tag "Colorado QSO Party" :value "CO-QSO-PARTY")
			       (item :tag "CQ WW 160 Meter DX Contest (CW)" :value "CQ-160-CW")
			       (item :tag "CQ WW 160 Meter DX Contest (SSB)" :value "CQ-160-SSB")
			       (item :tag "CQ-M International DX Contest" :value "CQ-M")
			       (item :tag "CQ World-Wide VHF Contest" :value "CQ-VHF")
			       (item :tag "CQ WW WPX Contest (CW)" :value "CQ-WPX-CW")
			       (item :tag "CQ/RJ WW RTTY WPX Contest" :value "CQ-WPX-RTTY")
			       (item :tag "CQ WW WPX Contest (SSB)" :value "CQ-WPX-SSB")
			       (item :tag "CQ WW DX Contest (CW)" :value "CQ-WW-CW")
			       (item :tag "CQ/RJ WW RTTY DX Contest" :value "CQ-WW-RTTY")
			       (item :tag "CQ WW DX Contest (SSB)" :value "CQ-WW-SSB")
			       (item :tag "Connecticut QSO Party" :value "CT-QSO-PARTY")
			       (item :tag "Concurso Verde e Amarelo DX CW Contest" :value "CVA-DX-CW")
			       (item :tag "Concurso Verde e Amarelo DX CW Contest" :value "CVA-DX-SSB")
			       (item :tag "CWops CW Open Competition" :value "CWOPS-CW-OPEN")
			       (item :tag "CWops Mini-CWT Test" :value "CWOPS-CWT")
			       (item :tag "WAE DX Contest (CW)" :value "DARC-WAEDC-CW")
			       (item :tag "WAE DX Contest (RTTY)" :value "DARC-WAEDC-RTTY")
			       (item :tag "WAE DX Contest (SSB)" :value "DARC-WAEDC-SSB")
			       (item :tag "DARC Worked All Germany" :value "DARC-WAG")
			       (item :tag "Delaware QSO Party" :value "DE-QSO-PARTY")
			       (item :tag "DL-DX RTTY Contest" :value "DL-DX-RTTY")
			       (item :tag "DMC RTTY Contest" :value "DMC-RTTY")
			       (item :tag "Concurso Nacional de Telegrafía" :value "EA-CNCW")
			       (item :tag "Municipios Españoles" :value "EA-DME")
			       (item :tag "His Majesty The King of Spain CW Contest (2022 and later)" :value "EA-MAJESTAD-CW")
			       (item :tag "His Majesty The King of Spain SSB Contest (2022 and later)" :value "EA-MAJESTAD-SSB")
			       (item :tag "EA PSK63" :value "EA-PSK63")
			       (item :tag "Unión de Radioaficionados Españoles RTTY Contest" :value "EA-RTTY (import-only)")
			       (item :tag "Su Majestad El Rey de España - CW (2021 and earlier)" :value "EA-SMRE-CW")
			       (item :tag "Su Majestad El Rey de España - SSB (2021 and earlier)" :value "EA-SMRE-SSB")
			       (item :tag "Atlántico V-UHF" :value "EA-VHF-ATLANTIC")
			       (item :tag "Combinado de V-UHF" :value "EA-VHF-COM")
			       (item :tag "Costa del Sol V-UHF" :value "EA-VHF-COSTA-SOL")
			       (item :tag "Nacional VHF" :value "EA-VHF-EA")
			       (item :tag "Segovia EA1RCS V-UHF" :value "EA-VHF-EA1RCS")
			       (item :tag "QSL V-UHF & 50MHz" :value "EA-VHF-QSL")
			       (item :tag "Sant Sadurni V-UHF" :value "EA-VHF-SADURNI")
			       (item :tag "Unión de Radioaficionados Españoles RTTY Contest" :value "EA-WW-RTTY")
			       (item :tag "PSK63 QSO Party" :value "EPC-PSK63")
			       (item :tag "EU Sprint" :value "EU Sprint")
			       (item :tag "EU HF Championship" :value "EU-HF")
			       (item :tag "EU PSK DX Contest" :value "EU-PSK-DX")
			       (item :tag "European CW Association 160m CW Party" :value "EUCW160M")
			       (item :tag "FISTS Fall Sprint" :value "FALL SPRINT")
			       (item :tag "Florida QSO Party" :value "FL-QSO-PARTY")
			       (item :tag "Georgia QSO Party" :value "GA-QSO-PARTY")
			       (item :tag "Hungarian DX Contest" :value "HA-DX")
			       (item :tag "Helvetia Contest" :value "HELVETIA")
			       (item :tag "Hawaiian QSO Party" :value "HI-QSO-PARTY")
			       (item :tag "IARC Holyland Contest" :value "HOLYLAND")
			       (item :tag "Iowa QSO Party" :value "IA-QSO-PARTY")
			       (item :tag "DARC IARU Region 1 Field Day" :value "IARU-FIELD-DAY")
			       (item :tag "IARU HF World Championship" :value "IARU-HF")
			       (item :tag "ICWC Medium Speed Test" :value "ICWC-MST")
			       (item :tag "Idaho QSO Party" :value "ID-QSO-PARTY")
			       (item :tag "Illinois QSO Party" :value "IL QSO Party")
			       (item :tag "Indiana QSO Party" :value "IN-QSO-PARTY")
			       (item :tag "JARTS WW RTTY" :value "JARTS-WW-RTTY")
			       (item :tag "Japan International DX Contest (CW)" :value "JIDX-CW")
			       (item :tag "Japan International DX Contest (SSB)" :value "JIDX-SSB")
			       (item :tag "Mongolian RTTY DX Contest" :value "JT-DX-RTTY")
			       (item :tag "K1USN Slow Speed Test" :value "K1USN-SST")
			       (item :tag "Kansas QSO Party" :value "KS-QSO-PARTY")
			       (item :tag "Kentucky QSO Party" :value "KY-QSO-PARTY")
			       (item :tag "Louisiana QSO Party" :value "LA-QSO-PARTY")
			       (item :tag "DRCG Long Distance Contest (RTTY)" :value "LDC-RTTY")
			       (item :tag "LZ DX Contest" :value "LZ DX")
			       (item :tag "Maritimes QSO Party" :value "MAR-QSO-PARTY")
			       (item :tag "Maryland QSO Party" :value "MD-QSO-PARTY")
			       (item :tag "Maine QSO Party" :value "ME-QSO-PARTY")
			       (item :tag "Michigan QSO Party" :value "MI-QSO-PARTY")
			       (item :tag "Mid-Atlantic QSO Party" :value "MIDATLANTIC-QSO-PARTY")
			       (item :tag "Minnesota QSO Party" :value "MN-QSO-PARTY")
			       (item :tag "Missouri QSO Party" :value "MO-QSO-PARTY")
			       (item :tag "Mississippi QSO Party" :value "MS-QSO-PARTY")
			       (item :tag "Montana QSO Party" :value "MT-QSO-PARTY")
			       (item :tag "North America Sprint (CW)" :value "NA-SPRINT-CW")
			       (item :tag "North America Sprint (RTTY)" :value "NA-SPRINT-RTTY")
			       (item :tag "North America Sprint (Phone)" :value "NA-SPRINT-SSB")
			       (item :tag "North America QSO Party (CW)" :value "NAQP-CW")
			       (item :tag "North America QSO Party (RTTY)" :value "NAQP-RTTY")
			       (item :tag "North America QSO Party (Phone)" :value "NAQP-SSB")
			       (item :tag "North Carolina QSO Party" :value "NC-QSO-PARTY")
			       (item :tag "North Dakota QSO Party" :value "ND-QSO-PARTY")
			       (item :tag "Nebraska QSO Party" :value "NE-QSO-PARTY")
			       (item :tag "New England QSO Party" :value "NEQP")
			       (item :tag "New Hampshire QSO Party" :value "NH-QSO-PARTY")
			       (item :tag "New Jersey QSO Party" :value "NJ-QSO-PARTY")
			       (item :tag "New Mexico QSO Party" :value "NM-QSO-PARTY")
			       (item :tag "NRAU-Baltic Contest (CW)" :value "NRAU-BALTIC-CW")
			       (item :tag "NRAU-Baltic Contest (SSB)" :value "NRAU-BALTIC-SSB")
			       (item :tag "Nevada QSO Party" :value "NV-QSO-PARTY")
			       (item :tag "New York QSO Party" :value "NY-QSO-PARTY")
			       (item :tag "Oceania DX Contest (CW)" :value "OCEANIA-DX-CW")
			       (item :tag "Oceania DX Contest (SSB)" :value "OCEANIA-DX-SSB")
			       (item :tag "Ohio QSO Party" :value "OH-QSO-PARTY")
			       (item :tag "Czech Radio Club OK DX Contest" :value "OK-DX-RTTY")
			       (item :tag "Czech Radio Club OK-OM DX Contest" :value "OK-OM-DX")
			       (item :tag "Oklahoma QSO Party" :value "OK-QSO-PARTY")
			       (item :tag "Old Man International Sideband Society QSO Party" :value "OMISS-QSO-PARTY")
			       (item :tag "Ontario QSO Party" :value "ON-QSO-PARTY")
			       (item :tag "Oregon QSO Party" :value "OR-QSO-PARTY")
			       (item :tag "Pennsylvania QSO Party" :value "PA-QSO-PARTY")
			       (item :tag "Dutch PACC Contest" :value "PACC")
			       (item :tag "MDXA PSK DeathMatch (2005-2010)" :value "PSK-DEATHMATCH")
			       (item :tag "Quebec QSO Party" :value "QC-QSO-PARTY")
			       (item :tag "Canadian Amateur Radio Society Contest" :value "RAC (import-only)")
			       (item :tag "RAC Canada Day Contest" :value "RAC-CANADA-DAY")
			       (item :tag "RAC Canada Winter Contest" :value "RAC-CANADA-WINTER")
			       (item :tag "Russian District Award Contest" :value "RDAC")
			       (item :tag "Russian DX Contest" :value "RDXC")
			       (item :tag "Reseau des Emetteurs Francais 160m Contest" :value "REF-160M")
			       (item :tag "Reseau des Emetteurs Francais Contest (CW)" :value "REF-CW")
			       (item :tag "Reseau des Emetteurs Francais Contest (SSB)" :value "REF-SSB")
			       (item :tag "Rede dos Emissores Portugueses Portugal Day HF Contest" :value "REP-PORTUGAL-DAY-HF")
			       (item :tag "Rhode Island QSO Party" :value "RI-QSO-PARTY")
			       (item :tag "1.8MHz Contest" :value "RSGB-160")
			       (item :tag "21/28 MHz Contest (CW)" :value "RSGB-21/28-CW")
			       (item :tag "21/28 MHz Contest (SSB)" :value "RSGB-21/28-SSB")
			       (item :tag "80m Club Championships" :value "RSGB-80M-CC")
			       (item :tag "Affiliated Societies Team Contest (CW)" :value "RSGB-AFS-CW")
			       (item :tag "Affiliated Societies Team Contest (SSB)" :value "RSGB-AFS-SSB")
			       (item :tag "Club Calls" :value "RSGB-CLUB-CALLS")
			       (item :tag "Commonwealth Contest" :value "RSGB-COMMONWEALTH")
			       (item :tag "IOTA Contest" :value "RSGB-IOTA")
			       (item :tag "Low Power Field Day" :value "RSGB-LOW-POWER")
			       (item :tag "National Field Day" :value "RSGB-NFD")
			       (item :tag "RoPoCo" :value "RSGB-ROPOCO")
			       (item :tag "SSB Field Day" :value "RSGB-SSB-FD")
			       (item :tag "Russian Radio RTTY Worldwide Contest" :value "RUSSIAN-RTTY")
			       (item :tag "Scandinavian Activity Contest (CW)" :value "SAC-CW")
			       (item :tag "Scandinavian Activity Contest (SSB)" :value "SAC-SSB")
			       (item :tag "SARTG WW RTTY" :value "SARTG-RTTY")
			       (item :tag "South Carolina QSO Party" :value "SC-QSO-PARTY")
			       (item :tag "SCC RTTY Championship" :value "SCC-RTTY")
			       (item :tag "South Dakota QSO Party" :value "SD-QSO-PARTY")
			       (item :tag "SSA Portabeltest" :value "SMP-AUG")
			       (item :tag "SSA Portabeltest" :value "SMP-MAY")
			       (item :tag "PRC SPDX Contest (RTTY)" :value "SP-DX-RTTY")
			       (item :tag "SPAR Winter Field Day(2016 and earlier)" :value "SPAR-WINTER-FD")
			       (item :tag "SP DX Contest" :value "SPDXContest")
			       (item :tag "FISTS Spring Sprint" :value "SPRING SPRINT")
			       (item :tag "Scottish-Russian Marathon" :value "SR-MARATHON")
			       (item :tag "Stew Perry Topband Distance Challenge" :value "STEW-PERRY")
			       (item :tag "FISTS Summer Sprint" :value "SUMMER SPRINT")
			       (item :tag "TARA Grid Dip PSK-RTTY Shindig" :value "TARA-GRID-DIP")
			       (item :tag "TARA RTTY Mêlée" :value "TARA-RTTY")
			       (item :tag "TARA Rumble PSK Contest" :value "TARA-RUMBLE")
			       (item :tag "TARA Skirmish Digital Prefix Contest" :value "TARA-SKIRMISH")
			       (item :tag "Ten-Meter RTTY Contest (before 2011)" :value "TEN-RTTY")
			       (item :tag "The Makrothen Contest" :value "TMC-RTTY")
			       (item :tag "Tennessee QSO Party" :value "TN-QSO-PARTY")
			       (item :tag "Texas QSO Party" :value "TX-QSO-PARTY")
			       (item :tag "UBA Contest (CW)" :value "UBA-DX-CW")
			       (item :tag "UBA Contest (SSB)" :value "UBA-DX-SSB")
			       (item :tag "European PSK Club BPSK63 Contest" :value "UK-DX-BPSK63")
			       (item :tag "UK DX RTTY Contest" :value "UK-DX-RTTY")
			       (item :tag "Open Ukraine RTTY Championship" :value "UKR-CHAMP-RTTY")
			       (item :tag "Ukrainian DX" :value "UKRAINIAN DX")
			       (item :tag "UKSMG 6m Marathon" :value "UKSMG-6M-MARATHON")
			       (item :tag "UKSMG Summer Es Contest" :value "UKSMG-SUMMER-ES")
			       (item :tag "Ukrainian DX Contest" :value "URE-DX  (import-only)")
			       (item :tag "Mobile Amateur Awards Club" :value "US-COUNTIES-QSO")
			       (item :tag "Utah QSO Party" :value "UT-QSO-PARTY")
			       (item :tag "Virginia QSO Party" :value "VA-QSO-PARTY")
			       (item :tag "RCV Venezuelan Independence Day Contest" :value "VENEZ-IND-DAY")
			       (item :tag "Virginia QSO Party" :value "VIRGINIA QSO PARTY (import-only)")
			       (item :tag "Alessandro Volta RTTY DX Contest" :value "VOLTA-RTTY")
			       (item :tag "Vermont QSO Party" :value "VT-QSO-PARTY")
			       (item :tag "Washington QSO Party" :value "WA-QSO-PARTY")
			       (item :tag "Winter Field Day (2017 and later)" :value "WFD")
			       (item :tag "Wisconsin QSO Party" :value "WI-QSO-PARTY")
			       (item :tag "WIA Harry Angel Memorial 80m Sprint" :value "WIA-HARRY ANGEL")
			       (item :tag "WIA John Moyle Memorial Field Day" :value "WIA-JMMFD")
			       (item :tag "WIA Oceania DX (OCDX) Contest" :value "WIA-OCDX")
			       (item :tag "WIA Remembrance Day" :value "WIA-REMEMBRANCE")
			       (item :tag "WIA Ross Hull Memorial VHF/UHF Contest" :value "WIA-ROSS HULL")
			       (item :tag "WIA Trans Tasman Low Bands Challenge" :value "WIA-TRANS TASMAN")
			       (item :tag "WIA VHF UHF Field Days" :value "WIA-VHF/UHF FD")
			       (item :tag "WIA VK Shires" :value "WIA-VK SHIRES")
			       (item :tag "FISTS Winter Sprint" :value "WINTER SPRINT")
			       (item :tag "West Virginia QSO Party" :value "WV-QSO-PARTY")
			       (item :tag "World Wide Digi DX Contest" :value "WW-DIGI")
			       (item :tag "Wyoming QSO Party" :value "WY-QSO-PARTY")
			       (item :tag "Mexico International Contest (RTTY)" :value "XE-INTL-RTTY")
			       (item :tag "YODX HF contest" :value "YOHFDX")
			       (item :tag "YU DX Contest" :value "YUDXC")))
    (COUNTRY . (editable-field :format "COUNTRY: %v\n" :size 37 :value ""))
    (COUNTRY_INTL . (editable-field :format "COUNTRY_INTL: %v\n" :size 32 :value ""))
    (CQZ . (editable-field :format "CQZ: %v\n" :size 40 :value ""))
    (CREDIT_SUBMITTED . (editable-field :format "CREDIT_SUBMITTED: %v\n" :size 40 :value ""))
    (CREDIT_GRANTED . (editable-field :format "CREDIT_GRANTED: %v\n" :size 40 :value ""))
    (DARC_DOK . (editable-field :format "DARC_DOK: %v\n" :size 40 :value ""))
    (DISTANCE . (editable-field :format "DISTANCE: %v\n" :size 40 :value ""))
    (DXCC . (editable-field :format "DXCC: %v\n" :size 40 :value ""))
    (EMAIL . (editable-field :format "EMAIL: %v\n" :size 39 :value ""))
    (EQ_CALL . (editable-field :format "EQ_CALL: %v\n" :size 40 :value ""))
    (EQSL_QSLRDATE . (editable-field :format "EQSL_QSLRDATE: %v\n" :size 40 :value ""))
    (EQSL_QSLSDATE . (editable-field :format "EQSL_QSLSDATE: %v\n" :size 40 :value ""))
    (EQSL_QSL_RCVD . (editable-field :format "EQSL_QSL_RCVD: %v\n" :size 40 :value ""))
    (EQSL_QSL_SENT . (editable-field :format "EQSL_QSL_SENT: %v\n" :size 40 :value ""))
    (FISTS . (editable-field :format "FISTS: %v\n" :size 40 :value ""))
    (FISTS_CC . (editable-field :format "FISTS_CC: %v\n" :size 40 :value ""))
    (FORCE_INIT . (editable-field :format "FORCE_INIT: %v\n" :size 40 :value ""))
    (FREQ . (editable-field :format "FREQ: %vMHz\n" :size 10 :value ""))
    (FREQ_RX . (editable-field :format "FREQ_RX: %vMHz\n" :size 10 :value ""))
    (GRIDSQUARE . (editable-field :format "GRIDSQUARE: %v\n" :size 6 :value ""))
    (GRIDSQUARE_EXT . (editable-field :format "GRIDSQUARE_EXT: %v\n" :size 6 :value ""))
    (GUEST_OP . (editable-field :format "GUEST_OP: %v\n" :size 36 :value ""))
    (HAMLOGEU_QSO_UPLOAD_DATE . (editable-field :format "HAMLOGEU_QSO_UPLOAD_DATE: %v\n" :size 40 :value ""))
    (HAMLOGEU_QSO_UPLOAD_STATUS . (editable-field :format "HAMLOGEU_QSO_UPLOAD_STATUS: %v\n" :size 40 :value ""))
    (HAMQTH_QSO_UPLOAD_DATE . (editable-field :format "HAMQTH_QSO_UPLOAD_DATE: %v\n" :size 40 :value ""))
    (HAMQTH_QSO_UPLOAD_STATUS . (editable-field :format "HAMQTH_QSO_UPLOAD_STATUS: %v\n" :size 40 :value ""))
    (HRDLOG_QSO_UPLOAD_DATE . (editable-field :format "HRDLOG_QSO_UPLOAD_DATE: %v\n" :size 40 :value ""))
    (HRDLOG_QSO_UPLOAD_STATUS . (editable-field :format "HRDLOG_QSO_UPLOAD_STATUS: %v\n" :size 40 :value ""))
    (IOTA . (editable-field :format "IOTA: %v\n" :size 40 :value ""))
    (IOTA_ISLAND_ID . (editable-field :format "IOTA_ISLAND_ID: %v\n" :size 40 :value ""))
    (ITUZ . (editable-field :format "ITUZ: %v\n" :size 40 :value ""))
    (K_INDEX . (editable-field :format "K_INDEX: %v\n" :size 3 :value ""))
    (LAT . (editable-field :format "LAT: %v\n" :size 11 :value ""))
    (LON . (editable-field :format "LON: %v\n" :size 11 :value ""))
    (LOTW_QSLRDATE . (editable-field :format "LOTW_QSLRDATE: %v\n" :size 40 :value ""))
    (LOTW_QSLSDATE . (editable-field :format "LOTW_QSLSDATE: %v\n" :size 40 :value ""))
    (LOTW_QSL_RCVD . (editable-field :format "LOTW_QSL_RCVD: %v\n" :size 40 :value ""))
    (LOTW_QSL_SENT . (editable-field :format "LOTW_QSL_SENT: %v\n" :size 40 :value ""))
    (MAX_BURSTS . (editable-field :format "MAX_BURSTS: %v\n" :size 40 :value ""))
    (MODE . (menu-choice :tag "MODE" :format "MODE: %[%v%]" :value ""
			  (item :tag "AM" :value "AM")
			  (item :tag "ARDOP" :value "ARDOP")
			  (item :tag "ATV" :value "ATV")
			  (item :tag "CHIP" :value "CHIP")
			  (item :tag "CLO" :value "CLO")
			  (item :tag "CONTESTI" :value "CONTESTI")
			  (item :tag "CW" :value "CW")
			  (item :tag "DIGITALVOICE" :value "DIGITALVOICE")
			  (item :tag "DOMINO" :value "DOMINO")
			  (item :tag "DYNAMIC" :value "DYNAMIC")
			  (item :tag "FAX" :value "FAX")
			  (item :tag "FM" :value "FM")
			  (item :tag "FSK441" :value "FSK441")
			  (item :tag "FT8" :value "FT8")
			  (item :tag "HELL" :value "HELL")
			  (item :tag "ISCAT" :value "ISCAT")
			  (item :tag "JT4" :value "JT4")
			  (item :tag "JT6M" :value "JT6M")
			  (item :tag "JT9" :value "JT9")
			  (item :tag "JT44" :value "JT44")
			  (item :tag "JT65" :value "JT65")
			  (item :tag "MFSK" :value "MFSK")
			  (item :tag "MSK144" :value "MSK144")
			  (item :tag "MT63" :value "MT63")
			  (item :tag "OLIVIA" :value "OLIVIA")
			  (item :tag "OPERA" :value "OPERA")
			  (item :tag "PAC" :value "PAC")
			  (item :tag "PAX" :value "PAX")
			  (item :tag "PKT" :value "PKT")
			  (item :tag "PSK" :value "PSK")
			  (item :tag "PSK2K" :value "PSK2K")
			  (item :tag "Q15" :value "Q15")
			  (item :tag "QRA64" :value "QRA64")
			  (item :tag "ROS" :value "ROS")
			  (item :tag "RTTY" :value "RTTY")
			  (item :tag "RTTYM" :value "RTTYM")
			  (item :tag "SSB" :value "SSB")
			  (item :tag "SSTV" :value "SSTV")
			  (item :tag "T10" :value "T10")
			  (item :tag "THOR" :value "THOR")
			  (item :tag "THRB" :value "THRB")
			  (item :tag "TOR" :value "TOR")
			  (item :tag "V4" :value "V4")
			  (item :tag "VOI" :value "VOI")
			  (item :tag "WINMOR" :value "WINMOR")
			  (item :tag "WSPR" :value "WSPR")))
    (MS_SHOWER . (editable-field :format "MS_SHOWER: %v\n" :size 40 :value ""))
    (MY_ALTITUDE . (editable-field :format "MY_ALTITUDE: %v\n" :size 40 :value ""))
    (MY_ANTENNA . (editable-field :format "MY_ANTENNA: %v\n" :size 40 :value ""))
    (MY_ARRL_SECT . (editable-field :format "MY_ARRL_SECT: %v\n" :size 3 :value ""))
    (MY_CITY . (editable-field :format "MY_CITY: %v\n" :size 40 :value ""))
    (MY_CITY_INTL . (editable-field :format "MY_CITY_INTL: %v\n" :size 40 :value ""))
    (MY_CNTY . (editable-field :format "MY_CNTY: %v\n" :size 40 :value ""))
    (MY_COUNTRY . (editable-field :format "MY_COUNTRY: %v\n" :size 40 :value ""))
    (MY_COUNTRY_INTL . (editable-field :format "MY_COUNTRY_INTL: %v\n" :size 40 :value ""))
    (MY_CQ_ZONE . (editable-field :format "MY_CQ_ZONE: %v\n" :size 40 :value ""))
    (MY_DXCC . (editable-field :format "MY_DXCC: %v\n" :size 40 :value ""))
    (MY_FISTS . (editable-field :format "MY_FISTS: %v\n" :size 40 :value ""))
    (MY_GRIDSQUARE . (editable-field :format "MY_GRIDSQUARE: %v\n" :size 40 :value ""))
    (MY_GRIDSQUARE_EXT . (editable-field :format "MY_GRIDSQUARE_EXT: %v\n" :size 40 :value ""))
    (MY_IOTA . (editable-field :format "MY_IOTA: %v\n" :size 40 :value ""))
    (MY_IOTA_ISLAND_ID . (editable-field :format "MY_IOTA_ISLAND_ID: %v\n" :size 40 :value ""))
    (MY_ITU_ZONE . (editable-field :format "MY_ITU_ZONE: %v\n" :size 40 :value ""))
    (MY_LAT . (editable-field :format "MY_LAT: %v\n" :size 40 :value ""))
    (MY_LON . (editable-field :format "MY_LON: %v\n" :size 40 :value ""))
    (MY_NAME . (editable-field :format "MY_NAME: %v\n" :size 40 :value ""))
    (MY_NAME_INTL . (editable-field :format "MY_NAME_INTL: %v\n" :size 40 :value ""))
    (MY_POSTAL_CODE . (editable-field :format "MY_POSTAL_CODE: %v\n" :size 40 :value ""))
    (MY_POSTAL_CODE_INTL . (editable-field :format "MY_POSTAL_CODE_INTL: %v\n" :size 40 :value ""))
    (MY_POTA_REF . (editable-field :format "MY_POTA_REF: %v\n" :size 40 :value ""))
    (MY_RIG . (editable-field :format "MY_RIG: %v\n" :size 40 :value ""))
    (MY_RIG_INTL . (editable-field :format "MY_RIG_INTL: %v\n" :size 40 :value ""))
    (MY_SIG . (editable-field :format "MY_SIG: %v\n" :size 40 :value ""))
    (MY_SIG_INTL . (editable-field :format "MY_SIG_INTL: %v\n" :size 40 :value ""))
    (MY_SIG_INFO . (editable-field :format "MY_SIG_INFO: %v\n" :size 40 :value ""))
    (MY_SIG_INFO_INTL . (editable-field :format "MY_SIG_INFO_INTL: %v\n" :size 40 :value ""))
    (MY_SOTA_REF . (editable-field :format "MY_SOTA_REF: %v\n" :size 40 :value ""))
    (MY_STATE . (editable-field :format "MY_STATE: %v\n" :size 40 :value ""))
    (MY_STREET . (editable-field :format "MY_STREET: %v\n" :size 40 :value ""))
    (MY_STREET_INTL . (editable-field :format "MY_STREET_INTL: %v\n" :size 40 :value ""))
    (MY_USACA_COUNTIES . (editable-field :format "MY_USACA_COUNTIES: %v\n" :size 40 :value ""))
    (MY_VUCC_GRIDS . (editable-field :format "MY_VUCC_GRIDS: %v\n" :size 40 :value ""))
    (MY_WWFF_REF . (editable-field :format "MY_WWFF_REF: %v\n" :size 40 :value ""))
    (NAME . (editable-field :format "NAME: %v\n" :size 40 :value ""))
    (NAME_INTL . (editable-field :format "NAME_INTL: %v\n" :size 40 :value ""))
    (NOTES . (editable-field :format "NOTES: %v\n" :size 40 :value ""))
    (NOTES_INTL . (editable-field :format "NOTES_INTL: %v\n" :size 40 :value ""))
    (NR_BURSTS . (editable-field :format "NR_BURSTS: %v\n" :size 40 :value ""))
    (NR_PINGS . (editable-field :format "NR_PINGS: %v\n" :size 40 :value ""))
;    (OPERATOR . (editable-field :format "OPERATOR: %v\n" :size 40 :value ""))
    (OWNER_CALLSIGN . (editable-field :format "OWNER_CALLSIGN: %v\n" :size 10 :value ""))
    (PFX . (editable-field :format "PFX: %v\n" :size 40 :value ""))
    (POTA_REF . (editable-field :format "POTA_REF: %v\n" :size 40 :value ""))
    (PRECEDENCE . (editable-field :format "PRECEDENCE: %v\n" :size 40 :value ""))
    (PROP_MODE . (menu-choice :tag "PROP_MODE" :format "PROP_MODE: %[%v%]" :value ""
			      (item :tag "Aircraft Scatter" :value "AS")
			      (item :tag "Aurora-E" :value "AUE")
			      (item :tag "Aurora" :value "AUR")
			      (item :tag "Back scatter" :value "BS")
			      (item :tag "EchoLink" :value "ECH")
			      (item :tag "Earth-Moon-Earth" :value "EME")
			      (item :tag "Sporadic E" :value "ES")
			      (item :tag "F2 Reflection" :value "F2")
			      (item :tag "Field Aligned Irregularities" :value "FAI")
			      (item :tag "Ground Wave" :value "GWAVE")
			      (item :tag "Internet-assisted" :value "INTERNET")
			      (item :tag "Ionoscatter" :value "ION")
			      (item :tag "IRLP" :value "IRL")
			      (item :tag "Line of Sight (includes transmission through obstacles such as walls)" :value "LOS")
			      (item :tag "Meteor scatter" :value "MS")
			      (item :tag "Terrestrial or atmospheric repeater or transponder" :value "RPT")
			      (item :tag "Rain scatter" :value "RS")
			      (item :tag "Satellite" :value "SAT")
			      (item :tag "Trans-equatorial" :value "TEP")
			      (item :tag "Tropospheric ducting" :value "TR")))
    (PUBLIC_KEY . (editable-field :format "PUBLIC_KEY: %v\n" :size 40 :value ""))
    (QRZCOM_QSO_UPLOAD_DATE . (editable-field :format "QRZCOM_QSO_UPLOAD_DATE: %v\n" :size 40 :value ""))
    (QRZCOM_QSO_UPLOAD_STATUS . (editable-field :format "QRZCOM_QSO_UPLOAD_STATUS: %v\n" :size 40 :value ""))
    (QSLMSG . (editable-field :format "QSLMSG: %v\n" :size 40 :value ""))
    (QSLMSG_INTL . (editable-field :format "QSLMSG_INTL: %v\n" :size 40 :value ""))
    (QSLRDATE . (editable-field :format "QSLRDATE: %v\n" :size 8 :value ""))
    (QSLSDATE . (editable-field :format "QSLSDATE: %v\n" :size 8 :value ""))
    (QSL_RCVD . (editable-field :format "QSL_RCVD: %v\n" :size 1 :value ""))
    (QSL_RCVD_VIA . (editable-field :format "QSL_RCVD_VIA: %v\n" :size 1 :value ""))
    (QSL_SENT . (editable-field :format "QSL_SENT: %v\n" :size 1 :value ""))
    (QSL_SENT_VIA . (editable-field :format "QSL_SENT_VIA: %v\n" :size 1 :value ""))
    (QSL_VIA . (editable-field :format "QSL_VIA: %v\n" :size 1 :value ""))
    (QSO_COMPLETE . (editable-field :format "QSO_COMPLETE: %v\n" :size 3 :value ""))
    (QSO_DATE . (editable-field :format "QSO_DATE: %v\n" :size 8 :value ""))
    (QSO_DATE_OFF . (editable-field :format "QSO_DATE_OFF: %v\n" :size 8 :value ""))
    (QSO_RANDOM . (editable-field :format "QSO_RANDOM: %v\n" :size 1 :value ""))
    (QTH . (editable-field :format "QTH: %v\n" :size 40 :value ""))
    (QTH_INTL . (editable-field :format "QTH_INTL: %v\n" :size 40 :value ""))
    (REGION . (editable-field :format "REGION: %v\n" :size 40 :value ""))
    (RIG . (editable-field :format "RIG: %v\n" :size 40 :value ""))
    (RIG_INTL . (editable-field :format "RIG_INTL: %v\n" :size 40 :value ""))
    (RST_RCVD . (editable-field :format "RST_RCVD: %v\n" :size 6 :value ""))
    (RST_SENT . (editable-field :format "RST_SENT: %v\n" :size 6 :value ""))
    (RX_PWR . (editable-field :format "RX_PWR: %vW\n" :size 6 :value ""))
    (SAT_MODE . (editable-field :format "SAT_MODE: %v\n" :size 40 :value ""))
    (SAT_NAME . (editable-field :format "SAT_NAME: %v\n" :size 40 :value ""))
    (SFI . (editable-field :format "SFI: %v\n" :size 40 :value ""))
    (SIG . (editable-field :format "SIG: %v\n" :size 40 :value ""))
    (SIG_INTL . (editable-field :format "SIG_INTL: %v\n" :size 40 :value ""))
    (SIG_INFO . (editable-field :format "SIG_INFO: %v\n" :size 40 :value ""))
    (SIG_INFO_INTL . (editable-field :format "SIG_INFO_INTL: %v\n" :size 40 :value ""))
    (SILENT_KEY . (editable-field :format "SILENT_KEY: %v\n" :size 1 :value ""))
    (SKCC . (editable-field :format "SKCC: %v\n" :size 40 :value ""))
    (SOTA_REF . (editable-field :format "SOTA_REF: %v\n" :size 40 :value ""))
    (SRX . (editable-field :format "SRX: %v\n" :size 6 :value ""))
    (SRX_STRING . (editable-field :format "SRX_STRING: %v\n" :size 40 :value ""))
    (STATE . (editable-field :format "STATE: %v\n" :size 40 :value ""))
    (STATION_CALLSIGN . (editable-field :format "STATION_CALLSIGN: %v\n" :size 40 :value ""))
    (STX . (editable-field :format "STX: %v\n" :size 40 :value ""))
    (STX_STRING . (editable-field :format "STX_STRING: %v\n" :size 40 :value ""))
    (SUBMODE . (menu-choice :format "SUBMODE: %[%v%]" :value ""
			    (item :tag "8PSK125 (PSK)" :value "8PSK125")
			    (item :tag "8PSK125F (PSK)" :value "8PSK125F")
			    (item :tag "8PSK125FL (PSK)" :value "8PSK125FL")
			    (item :tag "8PSK250 (PSK)" :value "8PSK250")
			    (item :tag "8PSK250F (PSK)" :value "8PSK250F")
			    (item :tag "8PSK250FL (PSK)" :value "8PSK250FL")
			    (item :tag "8PSK500 (PSK)" :value "8PSK500")
			    (item :tag "8PSK500F (PSK)" :value "8PSK500F")
			    (item :tag "8PSK1000 (PSK)" :value "8PSK1000")
			    (item :tag "8PSK1000F (PSK)" :value "8PSK1000F")
			    (item :tag "8PSK1200F (PSK)" :value "8PSK1200F")
			    (item :tag "AMTORFEC (TOR)" :value "AMTORFEC")
			    (item :tag "ASCI (RTTY)" :value "ASCI")
			    (item :tag "C4FM (DIGITALVOICE)" :value "C4FM")
			    (item :tag "CHIP64 (CHIP)" :value "CHIP64")
			    (item :tag "CHIP128 (CHIP)" :value "CHIP128")
			    (item :tag "DMR (DIGITALVOICE)" :value "DMR")
			    (item :tag "DOM-M (DOMINO)" :value "DOM-M")
			    (item :tag "DOM4 (DOMINO)" :value "DOM4")
			    (item :tag "DOM5 (DOMINO)" :value "DOM5")
			    (item :tag "DOM8 (DOMINO)" :value "DOM8")
			    (item :tag "DOM11 (DOMINO)" :value "DOM11")
			    (item :tag "DOM16 (DOMINO)" :value "DOM16")
			    (item :tag "DOM22 (DOMINO)" :value "DOM22")
			    (item :tag "DOM44 (DOMINO)" :value "DOM44")
			    (item :tag "DOM88 (DOMINO)" :value "DOM88")
			    (item :tag "DOMINOEX (DOMINO)" :value "DOMINOEX")
			    (item :tag "DOMINOF (DOMINO)" :value "DOMINOF")
			    (item :tag "DSTAR (DIGITALVOICE)" :value "DSTAR")
			    (item :tag "FMHELL (HELL)" :value "FMHELL")
			    (item :tag "FREEDV (DIGITALVOICE)" :value "FREEDV")
			    (item :tag "FSK31 (PSK)" :value "FSK31")
			    (item :tag "FSKHELL (HELL)" :value "FSKHELL")
			    (item :tag "FSQCALL (MFSK)" :value "FSQCALL")
			    (item :tag "FST4 (MFSK)" :value "FST4")
			    (item :tag "FST4W (MFSK)" :value "FST4W")
			    (item :tag "FT4 (MFSK)" :value "FT4")
			    (item :tag "GTOR (TOR)" :value "GTOR")
			    (item :tag "HELL80 (HELL)" :value "HELL80")
			    (item :tag "HELLX5 (HELL)" :value "HELLX5")
			    (item :tag "HELLX9 (HELL)" :value "HELLX9")
			    (item :tag "HFSK (HELL)" :value "HFSK")
			    (item :tag "ISCAT-A (ISCAT)" :value "ISCAT-A")
			    (item :tag "ISCAT-B (ISCAT)" :value "ISCAT-B")
			    (item :tag "JS8 (MFSK)" :value "JS8")
			    (item :tag "JT4A (JT4)" :value "JT4A")
			    (item :tag "JT4B (JT4)" :value "JT4B")
			    (item :tag "JT4C (JT4)" :value "JT4C")
			    (item :tag "JT4D (JT4)" :value "JT4D")
			    (item :tag "JT4E (JT4)" :value "JT4E")
			    (item :tag "JT4F (JT4)" :value "JT4F")
			    (item :tag "JT4G (JT4)" :value "JT4G")
			    (item :tag "JT9-1 (JT9)" :value "JT9-1")
			    (item :tag "JT9-2 (JT9)" :value "JT9-2")
			    (item :tag "JT9-5 (JT9)" :value "JT9-5")
			    (item :tag "JT9-10 (JT9)" :value "JT9-10")
			    (item :tag "JT9-30 (JT9)" :value "JT9-30")
			    (item :tag "JT9A (JT9)" :value "JT9A")
			    (item :tag "JT9B (JT9)" :value "JT9B")
			    (item :tag "JT9C (JT9)" :value "JT9C")
			    (item :tag "JT9D (JT9)" :value "JT9D")
			    (item :tag "JT9E (JT9)" :value "JT9E")
			    (item :tag "JT9E FAST (JT9)" :value "JT9E FAST")
			    (item :tag "JT9F (JT9)" :value "JT9F")
			    (item :tag "JT9F FAST (JT9)" :value "JT9F FAST")
			    (item :tag "JT9G (JT9)" :value "JT9G")
			    (item :tag "JT9G FAST (JT9)" :value "JT9G FAST")
			    (item :tag "JT9H (JT9)" :value "JT9H")
			    (item :tag "JT9H FAST (JT9)" :value "JT9H FAST")
			    (item :tag "JT65A (JT65)" :value "JT65A")
			    (item :tag "JT65B (JT65)" :value "JT65B")
			    (item :tag "JT65B2 (JT65)" :value "JT65B2")
			    (item :tag "JT65C (JT65)" :value "JT65C")
			    (item :tag "JT65C2 (JT65)" :value "JT65C2")
			    (item :tag "JTMS (MFSK)" :value "JTMS")
			    (item :tag "LSB (SSB)" :value "LSB")
			    (item :tag "M17 (DIGITALVOICE)" :value "M17")
			    (item :tag "MFSK4 (MFSK)" :value "MFSK4")
			    (item :tag "MFSK8 (MFSK)" :value "MFSK8")
			    (item :tag "MFSK11 (MFSK)" :value "MFSK11")
			    (item :tag "MFSK16 (MFSK)" :value "MFSK16")
			    (item :tag "MFSK22 (MFSK)" :value "MFSK22")
			    (item :tag "MFSK31 (MFSK)" :value "MFSK31")
			    (item :tag "MFSK32 (MFSK)" :value "MFSK32")
			    (item :tag "MFSK64 (MFSK)" :value "MFSK64")
			    (item :tag "MFSK64L (MFSK)" :value "MFSK64L")
			    (item :tag "MFSK128 (MFSK)" :value "MFSK128")
			    (item :tag "MFSK128L (MFSK)" :value "MFSK128L")
			    (item :tag "NAVTEX (TOR)" :value "NAVTEX")
			    (item :tag "OLIVIA 4/125 (OLIVIA)" :value "OLIVIA 4/125")
			    (item :tag "OLIVIA 4/250 (OLIVIA)" :value "OLIVIA 4/250")
			    (item :tag "OLIVIA 8/250 (OLIVIA)" :value "OLIVIA 8/250")
			    (item :tag "OLIVIA 8/500 (OLIVIA)" :value "OLIVIA 8/500")
			    (item :tag "OLIVIA 16/500 (OLIVIA)" :value "OLIVIA 16/500")
			    (item :tag "OLIVIA 16/1000 (OLIVIA)" :value "OLIVIA 16/1000")
			    (item :tag "OLIVIA 32/1000 (OLIVIA)" :value "OLIVIA 32/1000")
			    (item :tag "OPERA-BEACON (OPERA)" :value "OPERA-BEACON")
			    (item :tag "OPERA-QSO (OPERA)" :value "OPERA-QSO")
			    (item :tag "PAC2 (PAC)" :value "PAC2")
			    (item :tag "PAC3 (PAC)" :value "PAC3")
			    (item :tag "PAC4 (PAC)" :value "PAC4")
			    (item :tag "PAX2 (PAX)" :value "PAX2")
			    (item :tag "PCW (CW)" :value "PCW")
			    (item :tag "PSK10 (PSK)" :value "PSK10")
			    (item :tag "PSK31 (PSK)" :value "PSK31")
			    (item :tag "PSK63 (PSK)" :value "PSK63")
			    (item :tag "PSK63F (PSK)" :value "PSK63F")
			    (item :tag "PSK63RC10 (PSK)" :value "PSK63RC10")
			    (item :tag "PSK63RC20 (PSK)" :value "PSK63RC20")
			    (item :tag "PSK63RC32 (PSK)" :value "PSK63RC32")
			    (item :tag "PSK63RC4 (PSK)" :value "PSK63RC4")
			    (item :tag "PSK63RC5 (PSK)" :value "PSK63RC5")
			    (item :tag "PSK125 (PSK)" :value "PSK125")
			    (item :tag "PSK125RC10 (PSK)" :value "PSK125RC10")
			    (item :tag "PSK125RC12 (PSK)" :value "PSK125RC12")
			    (item :tag "PSK125RC16 (PSK)" :value "PSK125RC16")
			    (item :tag "PSK125RC4 (PSK)" :value "PSK125RC4")
			    (item :tag "PSK125RC5 (PSK)" :value "PSK125RC5")
			    (item :tag "PSK250 (PSK)" :value "PSK250")
			    (item :tag "PSK250RC2 (PSK)" :value "PSK250RC2")
			    (item :tag "PSK250RC3 (PSK)" :value "PSK250RC3")
			    (item :tag "PSK250RC5 (PSK)" :value "PSK250RC5")
			    (item :tag "PSK250RC6 (PSK)" :value "PSK250RC6")
			    (item :tag "PSK250RC7 (PSK)" :value "PSK250RC7")
			    (item :tag "PSK500 (PSK)" :value "PSK500")
			    (item :tag "PSK500RC2 (PSK)" :value "PSK500RC2")
			    (item :tag "PSK500RC3 (PSK)" :value "PSK500RC3")
			    (item :tag "PSK500RC4 (PSK)" :value "PSK500RC4")
			    (item :tag "PSK800RC2 (PSK)" :value "PSK800RC2")
			    (item :tag "PSK1000 (PSK)" :value "PSK1000")
			    (item :tag "PSK1000RC2 (PSK)" :value "PSK1000RC2")
			    (item :tag "PSKAM10 (PSK)" :value "PSKAM10")
			    (item :tag "PSKAM31 (PSK)" :value "PSKAM31")
			    (item :tag "PSKAM50 (PSK)" :value "PSKAM50")
			    (item :tag "PSKFEC31 (PSK)" :value "PSKFEC31")
			    (item :tag "PSKHELL (HELL)" :value "PSKHELL")
			    (item :tag "QPSK31 (PSK)" :value "QPSK31")
			    (item :tag "Q65 (MFSK)" :value "Q65")
			    (item :tag "QPSK63 (PSK)" :value "QPSK63")
			    (item :tag "QPSK125 (PSK)" :value "QPSK125")
			    (item :tag "QPSK250 (PSK)" :value "QPSK250")
			    (item :tag "QPSK500 (PSK)" :value "QPSK500")
			    (item :tag "QRA64A (QRA64)" :value "QRA64A")
			    (item :tag "QRA64B (QRA64)" :value "QRA64B")
			    (item :tag "QRA64C (QRA64)" :value "QRA64C")
			    (item :tag "QRA64D (QRA64)" :value "QRA64D")
			    (item :tag "QRA64E (QRA64)" :value "QRA64E")
			    (item :tag "ROS-EME (ROS)" :value "ROS-EME")
			    (item :tag "ROS-HF (ROS)" :value "ROS-HF")
			    (item :tag "ROS-MF (ROS)" :value "ROS-MF")
			    (item :tag "SIM31 (PSK)" :value "SIM31")
			    (item :tag "SITORB (TOR)" :value "SITORB")
			    (item :tag "SLOWHELL (HELL)" :value "SLOWHELL")
			    (item :tag "THOR-M (THOR)" :value "THOR-M")
			    (item :tag "THOR4 (THOR)" :value "THOR4")
			    (item :tag "THOR5 (THOR)" :value "THOR5")
			    (item :tag "THOR8 (THOR)" :value "THOR8")
			    (item :tag "THOR11 (THOR)" :value "THOR11")
			    (item :tag "THOR16 (THOR)" :value "THOR16")
			    (item :tag "THOR22 (THOR)" :value "THOR22")
			    (item :tag "THOR25X4 (THOR)" :value "THOR25X4")
			    (item :tag "THOR50X1 (THOR)" :value "THOR50X1")
			    (item :tag "THOR50X2 (THOR)" :value "THOR50X2")
			    (item :tag "THOR100 (THOR)" :value "THOR100")
			    (item :tag "THRBX (THRB)" :value "THRBX")
			    (item :tag "THRBX1 (THRB)" :value "THRBX1")
			    (item :tag "THRBX2 (THRB)" :value "THRBX2")
			    (item :tag "THRBX4 (THRB)" :value "THRBX4")
			    (item :tag "THROB1 (THRB)" :value "THROB1")
			    (item :tag "THROB2 (THRB)" :value "THROB2")
			    (item :tag "THROB4 (THRB)" :value "THROB4")
			    (item :tag "USB (SSB)" :value "USB")
			    (item :tag "VARA HF (DYNAMIC)" :value "VARA HF")
			    (item :tag "VARA SATELLITE (DYNAMIC)" :value "VARA SATELLITE")
			    (item :tag "VARA FM 1200 (DYNAMIC)" :value "VARA FM 1200")
			    (item :tag "VARA FM 9600 (DYNAMIC)" :value "VARA FM 9600")))
    (SWL . (editable-field :format "SWL: %v\n" :size 1 :value ""))
    (TEN_TEN . (editable-field :format "TEN_TEN: %v\n" :size 6 :value ""))
    (TIME_OFF . (editable-field :format "TIME_OFF: %v\n" :size 6 :value ""))
    (TIME_ON . (editable-field :format "TIME_ON: %v\n" :size 6 :value ""))
    (TX_PWR . (editable-field :format "TX_PWR: %vW\n" :size 6 :value ""))
    (UKSMG . (editable-field :format "UKSMG: %v\n" :size 40 :value ""))
    (USACA_COUNTIES . (editable-field :format "USACA_COUNTIES: %v\n" :size 40 :value ""))
    (VE_PROV . (editable-field :format "VE_PROV: %v\n" :size 40 :value ""))
    (VUCC_GRIDS . (editable-field :format "VUCC_GRIDS: %v\n" :size 40 :value ""))
    (WEB . (editable-field :format "WEB: %v\n" :size 41 :value ""))
    (WWFF_REF . (editable-field :format "WWFF_REF: %v\n" :size 40 :value ""))
    (custom-choice . (menu-choice :tag "Choose" :format "Choose: %[%v%]\n" :value "This"
                                  :help-echo "Choose me, please!"
                                  :notify (lambda (widget &rest ignore)
                                            (message "%s is a good choice!"
                                                     (widget-value widget)))
                                  (item :tag "This option" :value "This")
                                  (item :tag "That option" :value "That")
                                  (editable-field :menu-tag "No option" :value "Thus option"))))
  "QSO field definitions for the QSO Log Entry form.")


(defun qso-log-form ()
  "Create a dynamic QSO log form based on `qso-form-fields`."
  (interactive)
  (switch-to-buffer "*QSO Log Entry*")
  (kill-all-local-variables)
  (let ((inhibit-read-only t))
    (erase-buffer))
  (remove-overlays)
  (widget-insert "OPERATOR: " qso-OPERATOR " \n")
  (let ((widget-alist '()))
    ;; Create widgets for each field and store in widget-alist in the same order
    (dolist (field-info qso-form-fields)
      (let* ((field (car field-info))
             (clear-after-submit (cdr field-info))
             (field-definition (alist-get field qso-form-field-definitions)))
        (when field-definition
          (let ((widget (apply #'widget-create field-definition)))
            (setq widget-alist (append widget-alist (list (list field widget clear-after-submit))))
	    (when (eq field 'CALL)
	      (when qso-call-lookup
		(widget-create 'push-button
			       :notify (lambda (&rest _)
					 (let ((_adif-string "")
					       (call-value nil)
					       (_date-value "")
					       (_time-value ""))
					   ;; Collect data from each widget
					   (dolist (field-pair widget-alist)
					     (let* ((field (nth 0 field-pair))
						    (widget (nth 1 field-pair))
						    (_clear-after-submit (nth 2 field-pair))
						    (value (widget-value widget)))
					       (setq value (string-trim value)) ;; Remove whitespace
					       ;; Store the CALL value for duplicate check
					       (when (eq field 'CALL)
						 (setq call-value value))))
					   (let* ((url (format "https://callook.info/%s/text" call-value))
						  (buffer (url-retrieve-synchronously url)))
					     (if buffer
						 (with-current-buffer buffer
						   (goto-char (point-min))
						   (re-search-forward "^$" nil 'move)
						   (forward-line)
						   (let ((content (buffer-substring (point) (point-max))))
						     (with-current-buffer (get-buffer-create "*Callsign Info*")
						       (erase-buffer)
						       (insert content)
						       (goto-char (point-min))
						       (display-buffer (current-buffer))))))))
				       (message "Callsign Info Acquired"))
			       "Lookup"))
	      (when qso-call-lookup-autofill-name
		(widget-create 'push-button
			       :notify (lambda (&rest _)
					 (let ((_adif-string "")
					       (call-value nil)
					       (_date-value "")
					       (_time-value ""))
					   ;; Collect data from each widget
					   (dolist (field-pair widget-alist)
					     (let* ((field (nth 0 field-pair))
						    (widget (nth 1 field-pair))
						    (_clear-after-submit (nth 2 field-pair))
						    (value (widget-value widget)))
					       (setq value (string-trim value)) ;; Remove whitespace
					       ;; Store the CALL value for duplicate check
					       (when (eq field 'CALL)
						 (setq call-value value))))
					   (let* ((url (format "https://callook.info/%s/text" call-value))
						  (buffer (url-retrieve-synchronously url)))
					     (if buffer
						 (with-current-buffer buffer
						   (goto-char (point-min))
						   (re-search-forward "^$" nil 'move)
						   (forward-line)
						   (let ((content (buffer-substring (point) (point-max))))
						     (with-current-buffer (get-buffer-create "*Callsign Info*")
						       (erase-buffer)
						       (insert content)
						       (goto-char (point-min))
						       (display-buffer (current-buffer))))))))
					 (let ((info-buffer (get-buffer "*Callsign Info*")))
					   (if (null info-buffer)
					       (message "Error: No *Callsign Info* buffer found.")
					     (with-current-buffer info-buffer
					       (if (string-match-p "Invalid callsign!" (buffer-string))
						   (message "Error: Invalid callsign - Name field not populated.")
						 (let ((name-value nil))
						   (goto-char (point-min))
						   (if (re-search-forward "^Name \\+ Address:$" nil t)
						       (progn
							 (forward-line 1)
							 (setq name-value
							       (string-trim
								(buffer-substring
								 (line-beginning-position)
								 (line-end-position)))))
						     (message "Error: Could not find \"Name + Address:\" in *Callsign Info*."))
						   (when name-value
						     (let ((name-widget (nth 1 (assq 'NAME widget-alist))))
						       (if (null name-widget)
							   (message "Error: No \"Name\" field in QSO Log Entry - Name not populated.")
							 (widget-value-set name-widget name-value)
							 (widget-setup)
							 (message "Name autofilled: %s" name-value))))))))))
			       "Lookup/Autofill Name"))
	      (widget-insert "\n"))))))

    ;; Add submit, clear and quit buttons
    (widget-insert "\n")
    (widget-create 'push-button
                   :notify (lambda (&rest _)
                             (let ((adif-string "")
				   (call-value nil)
                                   (date-value "")
                                   (time-value ""))
                               ;; Collect data from each widget
                               (dolist (field-pair widget-alist)
                                 (let* ((field (nth 0 field-pair))
                                        (widget (nth 1 field-pair))
                                        (clear-after-submit (nth 2 field-pair))
                                        (value (widget-value widget)))
				   (setq value (string-trim value)) ;; Remove whitespace
                                   ;; Store the CALL value for duplicate check
                                   (when (eq field 'CALL)
                                     (setq call-value value))
				   ;; Generate the adif-string with non-empty field values
				   (unless (string-empty-p value)
                                     (setq adif-string
                                           (concat adif-string
                                                   (format "<%s:%d>%s"
                                                           (upcase (symbol-name field))
                                                           (length (format "%s" value))
                                                           value))))
                                   ;; Special handling for QSO_DATE and TIME_ON
                                   (when (eq field 'QSO_DATE)
                                     (setq date-value value))
                                   (when (eq field 'TIME_ON)
                                     (setq time-value value))
                                   ;; Clear the widget if it is marked for clearing
                                   (when clear-after-submit
                                     (widget-value-set widget ""))))
			       ;; If the ADIF file doesn't yet exist, create it and insert an ADIF header
			       (unless (file-exists-p qso-adif-path)
				 (make-empty-file qso-adif-path)
				 (with-temp-buffer
				   (let ((timestamp (format-time-string "%Y%m%d %H%M%S" (current-time) t)))
				     (insert (format "%s\n" qso-adif-title))
				     (insert "<ADIF_VER:5>3.1.4\n")
				     (insert (format "<CREATED_TIMESTAMP:15>%s\n" timestamp))
				     (insert "<PROGRAMID:16>Emacs-QSO-Logger\n<PROGRAMVERSION:5>1.0.6\n<EOH>\n"))
				   (write-region (point-min) (point-max) qso-adif-path t))
				 (message "File created, header written to file"))
			       ;; Check for duplicate callsign
			       (when (and qso-call-duplicates
					  call-value
					  (not (string-empty-p call-value)))
				 (let ((pattern (format "<CALL:%d>%s"
							(length (format "%s" call-value))
							(regexp-quote call-value)))
				       (occur-buf "*Occur*"))
				   (with-temp-buffer
				     (insert-file-contents qso-adif-path)
				     (occur pattern))
				   (when (get-buffer occur-buf)
				     (display-buffer occur-buf)
				     (let ((proceed (y-or-n-p "Duplicate(s) found — proceed anyway? ")))
				       (kill-buffer occur-buf)
				       (goto-char (point-min))
				       (widget-forward 1)
				       (unless proceed
					 (user-error "Submission canceled due to duplicate callsign"))))))
			       (progn
				 ;; Get the current UTC date and time if date and time fields are empty
				 (let* ((current-time (current-time))
					(utc-time (format-time-string "%Y%m%d %H%M%S" current-time t))
					(date (substring utc-time 0 8))
					(time (substring utc-time 9 15)))
				   (unless (and date-value (not (string-empty-p date-value)))
				     (setq date-value date))
				   (unless (and time-value (not (string-empty-p time-value)))
				     (setq time-value time))
				   ;; Auto-calculate BAND from FREQ if BAND not already included
				   (unless (string-match "<BAND:" adif-string)
				     (when (string-match "<FREQ:[0-9]+>\\([0-9.]+\\)" adif-string)
				       (let* ((freq-str (match-string 1 adif-string))
					      (freq (string-to-number freq-str))
					      (band
					       (cond
						((and (>= freq 1.8) (<= freq 2.0)) "160m")
						((and (>= freq 3.5) (<= freq 4.0)) "80m")
						((and (>= freq 5.3305) (<= freq 5.405)) "60m")
						((and (>= freq 7.0) (<= freq 7.3)) "40m")
						((and (>= freq 10.1) (<= freq 10.15)) "30m")
						((and (>= freq 14.0) (<= freq 14.35)) "20m")
						((and (>= freq 18.068) (<= freq 18.168)) "17m")
						((and (>= freq 21.0) (<= freq 21.45)) "15m")
						((and (>= freq 24.89) (<= freq 24.99)) "12m")
						((and (>= freq 28.0) (<= freq 29.7)) "10m")
						((and (>= freq 50.0) (<= freq 54.0)) "6m")
						((and (>= freq 144.0) (<= freq 148.0)) "2m")
						((and (>= freq 219.0) (<= freq 225.0)) "1.25m")
						((and (>= freq 430.0) (<= freq 450.0)) "70cm")
						(t nil))))
					 (when band
					   (setq adif-string
						 (concat adif-string
							 (format "<BAND:%d>%s" (length band) band)))))))
				   ;; Append date and time to the ADIF string
                                   (setq adif-string
                                         (concat adif-string
                                                 (format "<QSO_DATE:8>%s" date-value)
                                                 (format "<TIME_ON:6>%s" time-value)
						 "<OPERATOR:"
						 (format "%d" (length (format "%s" qso-OPERATOR))) ">"
						 (format "%s" qso-OPERATOR)"<eor>\n")))
				 ;; Append data to file
				 (with-temp-buffer
                                   (insert adif-string)
                                   (write-region (point-min) (point-max) qso-adif-path t))))
			     (goto-char (point-min))
			     (widget-forward 1)
			     (message "QSO logged!"))
		   "Submit")
    (widget-insert " ") ;; Add a space between buttons
    (widget-create 'push-button
                   :notify (lambda (&rest _)
                             (let ((_adif-string "")
				   (_call-value nil)
                                   (_date-value "")
                                   (_time-value ""))
                               ;; Collect data from each widget
                               (dolist (field-pair widget-alist)
                                 (let* ((_field (nth 0 field-pair))
                                        (widget (nth 1 field-pair))
                                        (clear-after-submit (nth 2 field-pair))
                                        (_value (widget-value widget)))
                                     (when clear-after-submit
                                       (widget-value-set widget "")))))
			     (goto-char (point-min))
			     (widget-forward 1))
                   "Clear")
    (widget-insert " ") ;; Add a space between buttons
    (widget-create 'push-button
                   :notify (lambda (&rest _)
                             (kill-buffer "*QSO Log Entry*"))
                   "Quit")
    (use-local-map widget-keymap)
    (widget-setup)
    (widget-forward 1)))
(provide 'qso)
;;; qso.el ends here
