From d4b1a038acf236618a01e162556108860d4de666 Mon Sep 17 00:00:00 2001 From: Stelios Bounanos Date: Tue, 26 May 2009 19:57:44 +0100 Subject: [PATCH] Merge flarq * Add flarq to build system and installers * Modify test scripts * Add flarq manual page * Add flarq command line argument handling * Improve flarq's windowing system support --- Makefile.am | 2 + configure.ac | 67 +- data/flarq.desktop | 9 + data/flarq.xpm | 975 ++++++++++++++ data/mac/flarq.icns | Bin 0 -> 40835 bytes data/win32/flarq.ico | Bin 0 -> 12206 bytes data/win32/fldigi.nsi | 181 ++- doc/Makefile.am | 20 +- doc/flarq.1.txt | 147 +++ m4/build.m4 | 69 +- m4/progs.m4 | 21 + scripts/mkappbundle.sh | 144 ++- scripts/mkhamlibstatic.sh | 2 +- scripts/mknsisinst.sh | 39 +- scripts/tests/config-h.sh | 7 +- scripts/tests/cr.sh | 2 +- src/Makefile.am | 176 ++- src/flarq-src/arq.cxx | 1460 +++++++++++++++++++++ src/flarq-src/arqdialogs.cxx | 732 +++++++++++ src/flarq-src/arqdialogs.fl | 445 +++++++ src/flarq-src/arqhelp.cxx | 183 +++ src/flarq-src/b64.cxx | 225 ++++ src/flarq-src/flarq.cxx | 1924 ++++++++++++++++++++++++++++ src/flarq-src/flarqenv.cxx | 301 +++++ src/flarq-src/flarqrc.rc | 5 + src/flarq-src/include/arq.h | 422 ++++++ src/flarq-src/include/arqdialogs.h | 89 ++ src/flarq-src/include/b64.h | 34 + src/flarq-src/include/flarq.h | 57 + src/flarq-src/include/flarqenv.h | 14 + src/include/pixmaps.h | 1 + src/include/pkg.h | 24 + src/main.cxx | 4 +- src/misc/icons.cxx | 3 +- src/misc/macros.cxx | 2 +- src/misc/pixmaps.cxx | 965 ++++++++++++++ src/misc/stacktrace.cxx | 10 +- 37 files changed, 8576 insertions(+), 185 deletions(-) create mode 100644 data/flarq.desktop create mode 100644 data/flarq.xpm create mode 100644 data/mac/flarq.icns create mode 100644 data/win32/flarq.ico create mode 100644 doc/flarq.1.txt create mode 100644 m4/progs.m4 create mode 100644 src/flarq-src/arq.cxx create mode 100644 src/flarq-src/arqdialogs.cxx create mode 100644 src/flarq-src/arqdialogs.fl create mode 100644 src/flarq-src/arqhelp.cxx create mode 100644 src/flarq-src/b64.cxx create mode 100644 src/flarq-src/flarq.cxx create mode 100644 src/flarq-src/flarqenv.cxx create mode 100644 src/flarq-src/flarqrc.rc create mode 100644 src/flarq-src/include/arq.h create mode 100644 src/flarq-src/include/arqdialogs.h create mode 100644 src/flarq-src/include/b64.h create mode 100644 src/flarq-src/include/flarq.h create mode 100644 src/flarq-src/include/flarqenv.h create mode 100644 src/include/pkg.h diff --git a/Makefile.am b/Makefile.am index 44b856f7..6cd8dc4a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,9 +18,11 @@ nsisinst: (cd src && $(MAKE) $(AM_MAKEFLAGS) $@) endif +if WANT_FLDIGI if ENABLE_HAMLIB hamlib-static: (cd src && $(MAKE) $(AM_MAKEFLAGS) $@) endif +endif EXTRA_DIST = build-aux/config.rpath diff --git a/configure.ac b/configure.ac index 6f784c1c..368a6eb2 100644 --- a/configure.ac +++ b/configure.ac @@ -8,19 +8,32 @@ AC_PREREQ(2.61) dnl major and minor must be integers; patch may dnl contain other characters or be empty m4_define(FLDIGI_MAJOR, [3]) -m4_define(FLDIGI_MINOR, [1]) -m4_define(FLDIGI_PATCH, [2AF]) +m4_define(FLDIGI_MINOR, [12]) +m4_define(FLDIGI_PATCH, [AF]) +m4_define(FLARQ_MAJOR, [4]) +m4_define(FLARQ_MINOR, [1]) +m4_define(FLARQ_PATCH, []) -AC_INIT([fldigi], FLDIGI_MAJOR.FLDIGI_MINOR[FLDIGI_PATCH], [w1hkj AT w1hkj DOT com]) +AC_INIT([fldigi], FLDIGI_MAJOR.FLDIGI_MINOR[]FLDIGI_PATCH, [w1hkj AT w1hkj DOT com]) # substitute in Makefiles AC_SUBST([FLDIGI_VERSION_MAJOR], [FLDIGI_MAJOR]) AC_SUBST([FLDIGI_VERSION_MINOR], [FLDIGI_MINOR]) AC_SUBST([FLDIGI_VERSION_PATCH], [FLDIGI_PATCH]) +AC_SUBST([FLDIGI_VERSION], [FLDIGI_MAJOR.FLDIGI_MINOR[]FLDIGI_PATCH]) +AC_SUBST([FLARQ_VERSION_MAJOR], [FLARQ_MAJOR]) +AC_SUBST([FLARQ_VERSION_MINOR], [FLARQ_MINOR]) +AC_SUBST([FLARQ_VERSION_PATCH], [FLARQ_PATCH]) +AC_SUBST([FLARQ_VERSION], [FLARQ_MAJOR.FLARQ_MINOR[]FLARQ_PATCH]) # define in config.h -AC_DEFINE([FLDIGI_VERSION_MAJOR], [FLDIGI_MAJOR], [Major version number]) -AC_DEFINE([FLDIGI_VERSION_MINOR], [FLDIGI_MINOR], [Minor version number]) -AC_DEFINE([FLDIGI_VERSION_PATCH], ["FLDIGI_PATCH"], [Patch/alpha version string]) +AC_DEFINE([FLDIGI_VERSION_MAJOR], [FLDIGI_MAJOR], [Fldigi major version number]) +AC_DEFINE([FLDIGI_VERSION_MINOR], [FLDIGI_MINOR], [Fldigi minor version number]) +AC_DEFINE([FLDIGI_VERSION_PATCH], ["FLDIGI_PATCH"], [Fldigi patch/alpha version string]) +AC_DEFINE([FLARQ_VERSION_MAJOR], [FLARQ_MAJOR], [Flarq major version number]) +AC_DEFINE([FLARQ_VERSION_MINOR], [FLARQ_MINOR], [Flarq minor version number]) +AC_DEFINE([FLARQ_VERSION_PATCH], ["FLARQ_PATCH"], [Flarq patch/alpha version string]) +AC_DEFINE([FLDIGI_VERSION], ["FLDIGI_MAJOR.FLDIGI_MINOR[]FLDIGI_PATCH"], [Fldigi version string]) +AC_DEFINE([FLARQ_VERSION], ["FLARQ_MAJOR.FLARQ_MINOR[]FLARQ_PATCH"], [Flarq version string]) AC_SUBST([AC_CONFIG_ARGS], [$ac_configure_args]) @@ -40,25 +53,30 @@ AC_CONFIG_HEADER([src/config.h]) AC_CONFIG_MACRO_DIR([m4]) -PACKAGE_AUTHORS="Dave Freese, Stelios Bounanos, Leigh Klotz, and others" +FLDIGI_AUTHORS="Dave Freese, Stelios Bounanos, Leigh Klotz, and others" +FLARQ_AUTHORS="Dave Freese" PACKAGE_HOME="http://www.w1hkj.com/Fldigi.html" PACKAGE_DL="http://www.w1hkj.com/Downloads.html" PACKAGE_PROJ="http://developer.berlios.de/project/showfiles.php?group_id=9149" PACKAGE_DOCS="http://www.w1hkj.com/FldigiHelp/index.html" PACKAGE_GUIDE="http://www.w1hkj.com/beginners.html" -AC_DEFINE_UNQUOTED([PACKAGE_AUTHORS], ["$PACKAGE_AUTHORS"], [Authors]) +FLARQ_DOCS="http://www.w1hkj.com/FlarqHelpFiles/flarq.html" +AC_DEFINE_UNQUOTED([FLDIGI_AUTHORS], ["$FLDIGI_AUTHORS"], [Fldigi authors]) +AC_DEFINE_UNQUOTED([FLARQ_AUTHORS], ["$FLARQ_AUTHORS"], [Flarq authors]) AC_DEFINE_UNQUOTED([PACKAGE_HOME], ["$PACKAGE_HOME"], [Home page]) AC_DEFINE_UNQUOTED([PACKAGE_DL], ["$PACKAGE_DL"], [Download page]) AC_DEFINE_UNQUOTED([PACKAGE_PROJ], ["$PACKAGE_PROJ"], [BerliOS page]) AC_DEFINE_UNQUOTED([PACKAGE_DOCS], ["$PACKAGE_DOCS"], [Docs index]) AC_DEFINE_UNQUOTED([PACKAGE_GUIDE], ["$PACKAGE_GUIDE"], [Beginners guide]) -AC_SUBST([PACKAGE_AUTHORS], [$PACKAGE_AUTHORS]) +AC_DEFINE_UNQUOTED([FLARQ_DOCS], ["$FLARQ_DOCS"], [Flarq Docs index]) +AC_SUBST([FLDIGI_AUTHORS], [$FLDIGI_AUTHORS]) +AC_SUBST([FLARQ_AUTHORS], [$FLARQ_AUTHORS]) AC_SUBST([PACKAGE_HOME], [$PACKAGE_HOME]) AC_SUBST([PACKAGE_DL], [$PACKAGE_DL]) AC_SUBST([PACKAGE_PROJ], [$PACKAGE_PROJ]) AC_SUBST([PACKAGE_DOCS], [$PACKAGE_DOCS]) AC_SUBST([PACKAGE_GUIDE], [$PACKAGE_GUIDE]) - +AC_SUBST([FLARQ_DOCS], [$FLARQ_DOCS]) # Checks for programs. @@ -108,6 +126,12 @@ AC_PRESERVE_HELP_ORDER AM_GNU_GETTEXT([external]) AM_CONDITIONAL([USE_NLS], [test "x$USE_NLS" = "xyes"]) +### Programs +# Determine if fldigi and flarq have been requested and can be built +# Set ac_cv_want_fldigi and ac_cv_want_flarq to yes/no +# Set WANT_FLDIGI and WANT_FLARQ Makefile conditionals +AC_FLDIGI_PROGRAMS + ###### OS support ### OSX # Set ac_cv_mac_universal to yes/no @@ -179,16 +203,18 @@ AC_FLDIGI_XMLRPC AC_FLDIGI_OSS ### libpng -# Set ac_cv_png to yes/no (not used because we require libpng) +# Required if $ac_cv_want_fldigi is "yes" +# Set ac_cv_png to yes/no (not used) # Define USE_PNG in config.h (as above) # Substitute PNG_CFLAGS and PNG_LIBS in Makefile -AC_FLDIGI_PKG_CHECK([png], [libpng >= 1.2.8], [no], [no]) +AC_FLDIGI_PKG_CHECK([png], [libpng >= 1.2.8], [$ac_cv_want_fldigi], [no]) ### libsamplerate -# Set ac_cv_samplerate to yes/no (not used because we require samplerate) +# Required if $ac_cv_want_fldigi is "yes" +# Set ac_cv_samplerate to yes/no (not used) # Define USE_SAMPLERATE in config.h (as above) # Substitute SAMPLERATE_CFLAGS and SAMPLERATE_LIBS in Makefile -AC_FLDIGI_PKG_CHECK([samplerate], [samplerate >= 0.1.1], [no], [no]) +AC_FLDIGI_PKG_CHECK([samplerate], [samplerate >= 0.1.1], [$ac_cv_want_fldigi], [no]) ### libsndfile # Set ac_cv_sndfile to yes/no @@ -252,6 +278,7 @@ AH_TOP([ #define CONFIG_H_ ]) AH_BOTTOM([ +#include "pkg.h" #include "util.h" #endif /* CONFIG_H_ */ ]) @@ -269,6 +296,15 @@ Configuration summary: CPU optimizations ........... $ac_cv_opt Debugging ................... $ac_cv_debug + fldigi ...................... $ac_cv_want_fldigi + flarq ....................... $ac_cv_want_flarq + + i18n ........................ $USE_NLS +]) + +if test "x$ac_cv_want_fldigi" = "xyes"; then + AC_MSG_RESULT([ fldigi build options: + sndfile ..................... $ac_cv_sndfile oss ......................... $ac_cv_oss portaudio ................... $ac_cv_portaudio @@ -276,6 +312,5 @@ Configuration summary: hamlib ...................... $ac_cv_hamlib xmlrpc ...................... $ac_cv_xmlrpc - - i18n ........................ $USE_NLS ]) +fi diff --git a/data/flarq.desktop b/data/flarq.desktop new file mode 100644 index 00000000..09fd21ca --- /dev/null +++ b/data/flarq.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=Flarq +GenericName=Fldigi ARQ Utility +Comment=Amateur Radio Data Transfer with ARQ +Exec=flarq +Icon=flarq +Terminal=false +Type=Application +Categories=Network;HamRadio; diff --git a/data/flarq.xpm b/data/flarq.xpm new file mode 100644 index 00000000..08d16c79 --- /dev/null +++ b/data/flarq.xpm @@ -0,0 +1,975 @@ +/* XPM */ +static char * flarq_xpm[] = { +"48 48 924 2", +" c None", +". c #5B1E0E", +"+ c #7F381B", +"@ c #A7624B", +"# c #A8624E", +"$ c #652012", +"% c #90555F", +"& c #AA7A86", +"* c #D4B5BE", +"= c #5E231C", +"- c #540900", +"; c #AC5D55", +"> c #B4644F", +", c #CF7F58", +"' c #FCAD85", +") c #FBB18F", +"! c #BA7057", +"~ c #965140", +"{ c #4F1509", +"] c #3B1314", +"^ c #45151B", +"/ c #895156", +"( c #AB8687", +"_ c #D7C6C1", +": c #FFFFFD", +"< c #FFFFFE", +"[ c #A58088", +"} c #945D68", +"| c #642D34", +"1 c #AC6352", +"2 c #A45C49", +"3 c #A35B46", +"4 c #CC8C74", +"5 c #F4B8A0", +"6 c #FAC5A8", +"7 c #FFD4B3", +"8 c #FFD8B8", +"9 c #FFDCBD", +"0 c #FFCFAC", +"a c #E7A380", +"b c #A2563C", +"c c #984D37", +"d c #A2787A", +"e c #997474", +"f c #AA8B91", +"g c #D1C0C6", +"h c #CAB3BD", +"i c #FBE6F1", +"j c #F9FFFF", +"k c #F8FAFA", +"l c #FEFFFF", +"m c #F3F2EF", +"n c #E9D7D9", +"o c #AC9092", +"p c #AC8C8D", +"q c #926A6E", +"r c #9A737B", +"s c #9B747C", +"t c #9E573C", +"u c #98543D", +"v c #9A5F47", +"w c #BF8469", +"x c #E9AE90", +"y c #FFCAA8", +"z c #FFD9B6", +"A c #FFDFBA", +"B c #FDE1BA", +"C c #FDDEB8", +"D c #FEDBBB", +"E c #FBDBC3", +"F c #F8DBC5", +"G c #FFDCC3", +"H c #FFD1AF", +"I c #FBB891", +"J c #E79B74", +"K c #9A4E30", +"L c #9B5644", +"M c #7D4F54", +"N c #D0BCBE", +"O c #F5EDE7", +"P c #FCF4EE", +"Q c #FFFAFC", +"R c #FFFFFF", +"S c #C7BDC6", +"T c #C4B0BD", +"U c #F4F3F8", +"V c #FDFCFF", +"W c #FFFDFF", +"X c #F7FFFF", +"Y c #DEDCDC", +"Z c #E6E1E1", +"` c #FFFAF9", +" . c #FFF3F5", +".. c #FFF4F7", +"+. c #E2D9DA", +"@. c #C1AEB5", +"#. c #C5A3AF", +"$. c #7B5057", +"%. c #7D2F24", +"&. c #C87559", +"*. c #EA9464", +"=. c #FFA873", +"-. c #FFB886", +";. c #FFC193", +">. c #FBBD92", +",. c #FBBE92", +"'. c #F9B98A", +"). c #FAB784", +"!. c #F8AE77", +"~. c #F9AC76", +"{. c #F3A97B", +"]. c #F3BB97", +"^. c #FDD7BD", +"/. c #FEDCC3", +"(. c #FFDBB4", +"_. c #FED2A6", +":. c #FEBF94", +"<. c #E89574", +"[. c #D07355", +"}. c #C06F4F", +"|. c #C09581", +"1. c #F0F1E9", +"2. c #E8FBF4", +"3. c #EEF9F3", +"4. c #FDFDFE", +"5. c #FDF8FE", +"6. c #EFE7ED", +"7. c #A6969F", +"8. c #F2E9EF", +"9. c #F7F9F9", +"0. c #FEFDFF", +"a. c #B2A3AC", +"b. c #CBBFC7", +"c. c #FCFBFE", +"d. c #F9F6F8", +"e. c #F5F8F7", +"f. c #F6FFFF", +"g. c #69302D", +"h. c #5D0100", +"i. c #A0402C", +"j. c #CC7D59", +"k. c #BF6F4E", +"l. c #C16645", +"m. c #F6996A", +"n. c #FCA264", +"o. c #F8995F", +"p. c #F3925E", +"q. c #F29968", +"r. c #F29F71", +"s. c #E79469", +"t. c #C26640", +"u. c #CF6A43", +"v. c #FD9366", +"w. c #FF9B68", +"x. c #F99B63", +"y. c #F19F6E", +"z. c #EEAB80", +"A. c #F8C59B", +"B. c #FBD3AB", +"C. c #FCD2AA", +"D. c #FCD9B1", +"E. c #F8D1AA", +"F. c #F9C596", +"G. c #FFB371", +"H. c #FEAC6B", +"I. c #D69B78", +"J. c #EAD5D1", +"K. c #ECF6FA", +"L. c #F1FAFB", +"M. c #FFFBFF", +"N. c #FDF4FB", +"O. c #FDFAFB", +"P. c #D3CACE", +"Q. c #D8C7CE", +"R. c #F6FAF8", +"S. c #FEFCFF", +"T. c #C4B4C0", +"U. c #D3C8D3", +"V. c #FAFBFF", +"W. c #FBFBFF", +"X. c #FBFDFF", +"Y. c #F7FEFF", +"Z. c #F8DEDA", +"`. c #B76C57", +" + c #D76E4E", +".+ c #F89463", +"++ c #F9A36A", +"@+ c #FFB783", +"#+ c #F5A27A", +"$+ c #D0744E", +"%+ c #EB9060", +"&+ c #E68655", +"*+ c #EA8855", +"=+ c #F1935B", +"-+ c #F0975D", +";+ c #D27B43", +">+ c #E18450", +",+ c #E98B5A", +"'+ c #DD7C50", +")+ c #D07242", +"!+ c #F9A06A", +"~+ c #FFA771", +"{+ c #F6A26B", +"]+ c #EE9D67", +"^+ c #EEA26D", +"/+ c #F2AA77", +"(+ c #ECA776", +"_+ c #EDAC7B", +":+ c #EEB17D", +"<+ c #F1A55D", +"[+ c #FFA45C", +"}+ c #DC855E", +"|+ c #D9A3A2", +"1+ c #F5F0FC", +"2+ c #E9F7FA", +"3+ c #F6FDFE", +"4+ c #FDFBFE", +"5+ c #F8F9F9", +"6+ c #D1CFD0", +"7+ c #CCB9C0", +"8+ c #F9FAF9", +"9+ c #FBFAFC", +"0+ c #F7F0F5", +"a+ c #D7C6D1", +"b+ c #E7E0EB", +"c+ c #EAF4FB", +"d+ c #F1F9FD", +"e+ c #F9FEFF", +"f+ c #F2FCFB", +"g+ c #F6F5F5", +"h+ c #CA9E8E", +"i+ c #F4A27A", +"j+ c #FAA77A", +"k+ c #F6B280", +"l+ c #F5C896", +"m+ c #FED8AD", +"n+ c #FFCFAB", +"o+ c #FFCCA8", +"p+ c #F8C39B", +"q+ c #F5BC9C", +"r+ c #F2B48F", +"s+ c #ECA878", +"t+ c #F3A86C", +"u+ c #FCAA68", +"v+ c #FAA664", +"w+ c #F9A76A", +"x+ c #EC9B65", +"y+ c #D38048", +"z+ c #E69056", +"A+ c #E0874E", +"B+ c #FAA26B", +"C+ c #FAA470", +"D+ c #F5A06F", +"E+ c #F59E6A", +"F+ c #FA9C62", +"G+ c #F99A5D", +"H+ c #F49E6C", +"I+ c #F89E63", +"J+ c #FF9D5E", +"K+ c #ED8F64", +"L+ c #B67466", +"M+ c #F5EBF0", +"N+ c #E4F6F9", +"O+ c #EAFCFA", +"P+ c #FDFFFF", +"Q+ c #F5F8F8", +"R+ c #E6E6E7", +"S+ c #BEAAB2", +"T+ c #E9E2E6", +"U+ c #FCF9FB", +"V+ c #DFCFD2", +"W+ c #C4AEB7", +"X+ c #FAF0F9", +"Y+ c #EAF0F6", +"Z+ c #F3F8FC", +"`+ c #FBFEFF", +" @ c #F8F9F8", +".@ c #EADFDD", +"+@ c #B47A60", +"@@ c #E99560", +"#@ c #F3BB8E", +"$@ c #FDD8B6", +"%@ c #FFDDC1", +"&@ c #FDCFB2", +"*@ c #FECEAD", +"=@ c #FBD0A7", +"-@ c #F7D3A7", +";@ c #FAD1AA", +">@ c #F9CAA1", +",@ c #F8C392", +"'@ c #FAB179", +")@ c #F9A468", +"!@ c #F9A166", +"~@ c #F69F67", +"{@ c #F9A470", +"]@ c #FDA56E", +"^@ c #F69A5A", +"/@ c #D37536", +"(@ c #D1753D", +"_@ c #EF9868", +":@ c #F8A67A", +"<@ c #F39F71", +"[@ c #FB9E68", +"}@ c #FF9D60", +"|@ c #FA9C65", +"1@ c #FAA06B", +"2@ c #FA9C63", +"3@ c #FDA26C", +"4@ c #D5926E", +"5@ c #F2DFDA", +"6@ c #F0F3FD", +"7@ c #EDF3F8", +"8@ c #FEFCFC", +"9@ c #F9FAFA", +"0@ c #F3F4F6", +"a@ c #A2929B", +"b@ c #C0B1BA", +"c@ c #C4B0B0", +"d@ c #AC9398", +"e@ c #FEF1F8", +"f@ c #EEF2F7", +"g@ c #F2F3F8", +"h@ c #FEF9FB", +"i@ c #FBF2F0", +"j@ c #EFD9D8", +"k@ c #E09D81", +"l@ c #F0A268", +"m@ c #F9CCA1", +"n@ c #FDD3B7", +"o@ c #F2B094", +"p@ c #F3A377", +"q@ c #F5A66E", +"r@ c #F4A873", +"s@ c #F3A476", +"t@ c #F4A66D", +"u@ c #F6A367", +"v@ c #F9A269", +"w@ c #FBA169", +"x@ c #FD9F69", +"y@ c #FC9F69", +"z@ c #FC9F68", +"A@ c #F99F65", +"B@ c #F4A471", +"C@ c #F9B385", +"D@ c #F6A36E", +"E@ c #F19359", +"F@ c #D1743D", +"G@ c #E3905E", +"H@ c #F5A370", +"I@ c #F59F69", +"J@ c #FAA062", +"K@ c #FBA05E", +"L@ c #F8A26B", +"M@ c #F9A46F", +"N@ c #FAA160", +"O@ c #EA9C62", +"P@ c #C3998A", +"Q@ c #F7EBFA", +"R@ c #EEEAF8", +"S@ c #F6F4F6", +"T@ c #FCFEFF", +"U@ c #F4F4F7", +"V@ c #E4DCE3", +"W@ c #D4C1CD", +"X@ c #F2F5FA", +"Y@ c #AEA19F", +"Z@ c #C2B0B5", +"`@ c #F9F8FC", +" # c #E5F2F8", +".# c #EAF5FB", +"+# c #F0F5F5", +"@# c #F9F7F7", +"## c #D3B3A9", +"$# c #DF916B", +"%# c #FAA76E", +"&# c #F3B787", +"*# c #F0AE84", +"=# c #EE9D6B", +"-# c #F6A15D", +";# c #F7A559", +"># c #F9A160", +",# c #FE9B68", +"'# c #FD9D67", +")# c #FC9F67", +"!# c #FA9F69", +"~# c #F9A06C", +"{# c #F69F6A", +"]# c #F5A067", +"^# c #F9A464", +"/# c #F5A35C", +"(# c #E9A779", +"_# c #F8D5C1", +":# c #FFCEAA", +"<# c #FAB079", +"[# c #E1884B", +"}# c #CD713A", +"|# c #F39961", +"1# c #FAA56C", +"2# c #F8A668", +"3# c #FFA864", +"4# c #EF9965", +"5# c #E59462", +"6# c #FBA360", +"7# c #F49958", +"8# c #BE8469", +"9# c #E7DAE0", +"0# c #EFF2FB", +"a# c #EBF0F3", +"b# c #FBFEFE", +"c# c #F6F6FA", +"d# c #FAF3FA", +"e# c #B7A0AF", +"f# c #C4C0C8", +"g# c #D4CECD", +"h# c #DED5DD", +"i# c #EEF5FC", +"j# c #E4F0FD", +"k# c #E6F2FC", +"l# c #EBF5FB", +"m# c #EAE0E9", +"n# c #B67A69", +"o# c #ED8F5B", +"p# c #FCA368", +"q# c #F59E66", +"r# c #F9A067", +"s# c #F9A165", +"t# c #F99F66", +"u# c #FAA069", +"v# c #FAA169", +"w# c #FAA166", +"x# c #F8A264", +"y# c #F7A262", +"z# c #F9A162", +"A# c #F59E5E", +"B# c #FCA464", +"C# c #F0A172", +"D# c #F8C7AA", +"E# c #FFDFBE", +"F# c #F7D7AF", +"G# c #F7C497", +"H# c #F19C6B", +"I# c #DC7947", +"J# c #E48552", +"K# c #DD8553", +"L# c #BF6033", +"M# c #E28B60", +"N# c #E99B6D", +"O# c #F2A367", +"P# c #FA9F60", +"Q# c #E89874", +"R# c #E2CBBF", +"S# c #E9F6F7", +"T# c #EAF1FA", +"U# c #F6F6FB", +"V# c #FAF9FC", +"W# c #F9F1FA", +"X# c #BBABB5", +"Y# c #BDAEB7", +"Z# c #DDCBCC", +"`# c #FBF1F9", +" $ c #EFEAF7", +".$ c #E9EFFC", +"+$ c #EAF0FC", +"@$ c #F1F6FE", +"#$ c #E2CDCB", +"$$ c #D28869", +"%$ c #FFA26B", +"&$ c #F99F64", +"*$ c #FAA065", +"=$ c #FAA167", +"-$ c #FAA168", +";$ c #F9A066", +">$ c #F7A168", +",$ c #F7A167", +"'$ c #F7A165", +")$ c #F9A163", +"!$ c #FB9F63", +"~$ c #FA9E65", +"{$ c #F89D64", +"]$ c #FEA667", +"^$ c #F4B072", +"/$ c #FBD2AB", +"($ c #FBDFCB", +"_$ c #F9DECA", +":$ c #FBCBAA", +"<$ c #EFA579", +"[$ c #D3764B", +"}$ c #AE4621", +"|$ c #EA865A", +"1$ c #F8A674", +"2$ c #F8A16F", +"3$ c #FAA66A", +"4$ c #E38A65", +"5$ c #D5AFA0", +"6$ c #F1FDFF", +"7$ c #E9EFFF", +"8$ c #EEEDFC", +"9$ c #F5F4FD", +"0$ c #F0EDF6", +"a$ c #F5E9EF", +"b$ c #C6AFB4", +"c$ c #A28385", +"d$ c #FFF7FE", +"e$ c #F1E8F9", +"f$ c #EBEFF9", +"g$ c #EBEFFA", +"h$ c #F0EFF8", +"i$ c #D5B09E", +"j$ c #ED9B6E", +"k$ c #FDA168", +"l$ c #F89F66", +"m$ c #F89F65", +"n$ c #F6A066", +"o$ c #F5A166", +"p$ c #F6A065", +"q$ c #F8A065", +"r$ c #F9A167", +"s$ c #FCA06A", +"t$ c #F99B68", +"u$ c #DA7F51", +"v$ c #E88B52", +"w$ c #F9A15D", +"x$ c #F1AF7D", +"y$ c #F8D0B1", +"z$ c #FBDCC7", +"A$ c #FDDEC9", +"B$ c #FED4B9", +"C$ c #FBBC9A", +"D$ c #E58C65", +"E$ c #DB794C", +"F$ c #F69F61", +"G$ c #FF9F61", +"H$ c #FD9D60", +"I$ c #FAA163", +"J$ c #F79C6E", +"K$ c #DCA289", +"L$ c #EAE3E3", +"M$ c #ECF2FF", +"N$ c #E7F0FB", +"O$ c #E7F3FA", +"P$ c #E7EFF2", +"Q$ c #FEF7F9", +"R$ c #B49DA0", +"S$ c #C0A5A8", +"T$ c #F7F6FB", +"U$ c #E9EAFB", +"V$ c #E9F0F8", +"W$ c #E9F0FA", +"X$ c #F5F1FA", +"Y$ c #DBAD8E", +"Z$ c #EF975E", +"`$ c #FBA16A", +" % c #F7A065", +".% c #F6A165", +"+% c #F6A067", +"@% c #F6A570", +"#% c #F4A673", +"$% c #EC9A6C", +"%% c #D1794A", +"&% c #E68752", +"*% c #FDA26F", +"=% c #F2A374", +"-% c #F9C29B", +";% c #FFE0C1", +">% c #FDDDBC", +",% c #F4C29D", +"'% c #E09266", +")% c #D67F46", +"!% c #FB9E5C", +"~% c #FF9D63", +"{% c #FBA972", +"]% c #CE805C", +"^% c #C8A39D", +"/% c #F2F5FD", +"(% c #EAF1F4", +"_% c #E6F2F3", +":% c #E6F5F4", +"<% c #E7F1F1", +"[% c #EAEDED", +"}% c #E6E0E3", +"|% c #E7F3F7", +"1% c #DEF1FD", +"2% c #E7F2FB", +"3% c #EBF3FB", +"4% c #E7D7DC", +"5% c #D5916A", +"6% c #FCA265", +"7% c #F89E68", +"8% c #F8A066", +"9% c #F29F67", +"0% c #EFA56E", +"a% c #FBC490", +"b% c #F6BC8A", +"c% c #E9A26E", +"d% c #D8834F", +"e% c #E58456", +"f% c #FF9B6E", +"g% c #FAA16D", +"h% c #EDB075", +"i% c #F3C790", +"j% c #FCD7AD", +"k% c #FED4B6", +"l% c #F6BB94", +"m% c #CE8350", +"n% c #D6854A", +"o% c #FBA16F", +"p% c #F39F6D", +"q% c #F1A86D", +"r% c #E89568", +"s% c #D79F8D", +"t% c #F4EDEE", +"u% c #F0EEF8", +"v% c #ECEEF6", +"w% c #ECEFF9", +"x% c #ECEDF7", +"y% c #F1F0FC", +"z% c #F0F4FA", +"A% c #E6F2F5", +"B% c #DCF5FD", +"C% c #E3EBF7", +"D% c #F9FBFF", +"E% c #C19A96", +"F% c #D57E55", +"G% c #FDA366", +"H% c #F99F67", +"I% c #F99F63", +"J% c #FA9F63", +"K% c #F99E64", +"L% c #F8A86F", +"M% c #F1A66F", +"N% c #F8B985", +"O% c #FDD4A2", +"P% c #F2BD89", +"Q% c #F5A971", +"R% c #E28955", +"S% c #D97847", +"T% c #F69962", +"U% c #F4A66A", +"V% c #E9A46A", +"W% c #F2AA79", +"X% c #F9AE84", +"Y% c #F6AB7C", +"Z% c #EA9B63", +"`% c #E49159", +" & c #FFA572", +".& c #FBA36B", +"+& c #F8A363", +"@& c #FFA66F", +"#& c #CE7F5A", +"$& c #E9CAC3", +"%& c #F2F3FF", +"&& c #EBEDFD", +"*& c #F1EFFF", +"=& c #F8F1FF", +"-& c #FAEFFE", +";& c #FDF8FF", +">& c #FCF4F9", +",& c #F4F9FA", +"'& c #F9F7FF", +")& c #FDE9EB", +"!& c #D99781", +"~& c #F59668", +"{& c #F8A165", +"]& c #F8A164", +"^& c #F7A063", +"/& c #F9A164", +"(& c #FBA069", +"_& c #D98350", +":& c #DA8954", +"<& c #E79A68", +"[& c #FAB887", +"}& c #F6B181", +"|& c #F5A46D", +"1& c #F4A15F", +"2& c #E6914E", +"3& c #D37D41", +"4& c #EA9569", +"5& c #F8A078", +"6& c #FC9E6C", +"7& c #FE9D5C", +"8& c #FF9F5B", +"9& c #FFA46B", +"0& c #E58B5F", +"a& c #F09769", +"b& c #F39562", +"c& c #F09762", +"d& c #EF9A6A", +"e& c #D67F58", +"f& c #BB8678", +"g& c #F6F6FF", +"h& c #F7F4FF", +"i& c #EADFE9", +"j& c #D8C4CE", +"k& c #DABEC8", +"l& c #E3C8DB", +"m& c #E9CAD1", +"n& c #ECD7D4", +"o& c #EEDFE4", +"p& c #B98787", +"q& c #D9805B", +"r& c #F9A266", +"s& c #F6A360", +"t& c #F79E64", +"u& c #F6A466", +"v& c #F6A465", +"w& c #F9A065", +"x& c #FD9E67", +"y& c #DC7E4D", +"z& c #C7693C", +"A& c #ED9167", +"B& c #F4976B", +"C& c #FBA160", +"D& c #FFAC67", +"E& c #F49B60", +"F& c #D6784A", +"G& c #E5895F", +"H& c #F09662", +"I& c #FFA866", +"J& c #FFAD6E", +"K& c #E07F5D", +"L& c #7B2B1B", +"M& c #853D24", +"N& c #963E27", +"O& c #8D472B", +"P& c #824730", +"Q& c #843A2A", +"R& c #712A23", +"S& c #BA9092", +"T& c #DABABA", +"U& c #8B6E6B", +"V& c #4D3232", +"W& c #5D2D3D", +"X& c #68353A", +"Y& c #734744", +"Z& c #6A4A4C", +"`& c #663235", +" * c #934833", +".* c #DF8766", +"+* c #F99766", +"@* c #FB9E61", +"#* c #FFA66E", +"$* c #FCA16D", +"%* c #F99E69", +"&* c #F7A169", +"** c #F3A266", +"=* c #F4A365", +"-* c #FB9F68", +";* c #F6A16A", +">* c #F6A16B", +",* c #FCA06C", +"'* c #FC9D69", +")* c #FF9D6B", +"!* c #FF9E6C", +"~* c #F69563", +"{* c #D67949", +"]* c #D47348", +"^* c #F79567", +"/* c #FA9F68", +"(* c #F9A265", +"_* c #FFA166", +":* c #FC9B65", +"<* c #E98D5B", +"[* c #C4683A", +"}* c #BE6339", +"|* c #B06D4E", +"1* c #732F25", +"2* c #64201E", +"3* c #8B463B", +"4* c #B6573A", +"5* c #D06B39", +"6* c #D37A42", +"7* c #F4986B", +"8* c #FC9C73", +"9* c #F99F6C", +"0* c #F4A766", +"a* c #F1A561", +"b* c #F49E63", +"c* c #FB9E6B", +"d* c #F7A069", +"e* c #F9A16A", +"f* c #FCA16C", +"g* c #FE9F6C", +"h* c #FFA06C", +"i* c #FBA468", +"j* c #F49D5F", +"k* c #ED925B", +"l* c #C86A3A", +"m* c #DF8653", +"n* c #FBA26F", +"o* c #F9A369", +"p* c #FFA673", +"q* c #F6936D", +"r* c #7C1705", +"s* c #7C3625", +"t* c #C76E51", +"u* c #DE7B53", +"v* c #CA693D", +"w* c #BF633B", +"x* c #E88C57", +"y* c #E98E54", +"z* c #F9A267", +"A* c #FEA86F", +"B* c #F4A167", +"C* c #F6A362", +"D* c #F19C5B", +"E* c #DD8848", +"F* c #E89255", +"G* c #E68F53", +"H* c #F49D63", +"I* c #FEA76D", +"J* c #FCA36A", +"K* c #FAA466", +"L* c #F29B5B", +"M* c #EC8E5C", +"N* c #DB8154", +"O* c #D6874F", +"P* c #E79659", +"Q* c #FFA778", +"R* c #D07B64", +"S* c #6E1913", +"T* c #6C1F18", +"U* c #963729", +"V* c #EC9366", +"W* c #FFB374", +"X* c #E98F56", +"Y* c #B24C23", +"Z* c #ED8661", +"`* c #E78B58", +" = c #FAA561", +".= c #F8A262", +"+= c #F6A164", +"@= c #F7A466", +"#= c #E49459", +"$= c #C16E36", +"%= c #E08C58", +"&= c #E1895C", +"*= c #EF9265", +"== c #FFA372", +"-= c #FEA36A", +";= c #F5A268", +">= c #F6AA6A", +",= c #DC8545", +"'= c #D47440", +")= c #C87153", +"!= c #69241A", +"~= c #AB5E46", +"{= c #E88666", +"]= c #E37B53", +"^= c #D26E43", +"/= c #F4996C", +"(= c #CC6C39", +"_= c #E5834A", +":= c #F39462", +"<= c #FA9F6F", +"[= c #F6A16D", +"}= c #F49F6B", +"|= c #F69E6D", +"1= c #DD7F55", +"2= c #C7653C", +"3= c #E7825E", +"4= c #E4895D", +"5= c #F1A364", +"6= c #FFAC66", +"7= c #FEA067", +"8= c #CD7151", +"9= c #6E2215", +"0= c #7F2427", +"a= c #902F20", +"b= c #E5895A", +"c= c #FFB175", +"d= c #F2915D", +"e= c #B7522B", +"f= c #C05D34", +"g= c #D67649", +"h= c #F69E68", +"i= c #FDA46B", +"j= c #FCA069", +"k= c #FFA46E", +"l= c #F49460", +"m= c #EB8E5D", +"n= c #D06F41", +"o= c #C9683C", +"p= c #D67D55", +"q= c #A55135", +"r= c #682616", +"s= c #8F4C2E", +"t= c #DE8C68", +"u= c #CA6E51", +"v= c #C4654C", +"w= c #FFA579", +"x= c #F09360", +"y= c #CC7345", +"z= c #DA844C", +"A= c #EE9556", +"B= c #F59D5E", +"C= c #FFB174", +"D= c #FFB075", +"E= c #FFB073", +"F= c #FFA472", +"G= c #B85D49", +"H= c #6C1515", +"I= c #8B5446", +"J= c #73251B", +"K= c #95402C", +"L= c #E48F68", +"M= c #FFAA79", +"N= c #F59D70", +"O= c #EB9061", +"P= c #E48A59", +"Q= c #C57046", +"R= c #B26340", +"S= c #B16947", +"T= c #B36943", +"U= c #A65D40", +"V= c #7B3629", +"W= c #6A230D", +"X= c #BA6848", +"Y= c #D57C5E", +"Z= c #D1745E", +"`= c #CE7260", +" - c #923C2D", +".- c #84382F", +"+- c #813F39", +"@- c #7B423B", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" . + @ # $ % & * ", +" = - ; > , ' ) ! ~ { ] ^ / ( _ : < ", +"[ } | 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l ", +"m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W ", +"X Y Z ` ...+.@.#.$. %.&.*.=.-.;.>.,.'.).!.~.{.].^./.9 (._.:.<.[.}.|.1.2.3.4.5.6.7.8.9.0.", +"R a.b.c.d.e.f.R W g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.", +"R T.U.V.W.X.Y.V Z.`. +.+++@+#+$+%+&+*+=+-+;+>+,+'+)+!+~+{+]+^+/+(+_+:+<+[+}+|+1+2+3+4+5+6+7+8+9+", +"0+a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+u+v+w+x+y+z+A+B+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+", +"V+W+X+Y+Z+`+ @.@+@@@#@$@%@&@*@=@-@;@>@,@'@)@!@~@{@]@^@/@(@_@:@<@[@}@|@1@2@3@4@5@6@7@8@9@0@a@b@R ", +"c@d@e@f@g@h@i@j@k@l@m@n@o@p@q@r@s@t@u@v@w@x@y@z@A@B@C@D@E@F@G@H@I@J@K@L@M@N@O@P@Q@R@S@T@U@V@W@X@", +"Y@Z@`@ #.#+#@###$#%#&#*#=#-#;#>#,#'#)#!#~#{#]#^#/#(#_#:#<#[#}#|#1#2#3#4#5#6#7#8#9#0#a#b#c#d#e#f#", +"g#h#i#j#k#l#m#n#o#p#~@q#r#s#s#s#t#u#v#w#x#y#z#A#B#C#D#E#F#G#H#I#J#K#L#M#N#O#P#Q#R#S#T#U#V#W#X#Y#", +"Z#`# $.$+$@$#$$$%$&$&$*$=$-$r#r#;$>$,$'$)$)$!$~${$]$^$/$($_$:$<$[$}$|$1$2$~@3$4$5$6$7$8$9$0$a$b$", +"c$d$e$f$g$h$i$j$k$A@;$=$;$;$l$m$m$n$o$p$q$r$s$t$u$v$w$x$y$z$A$B$C$D$E$F$G$H$I$J$K$L$M$N$O$P$Q$R$", +"S$T$U$V$W$X$Y$Z$`$;$=$;$=$=$;$;$;$ % %.% %+%@%#%$%%%&%*%=%-%D ;%>%,%'%)%!%~%t#{%]%^%/%(%_%:%<%[%", +"}%|%1%2%3%4%5%6%7%r#=$m$;$;$=$;$8%&$&$q$+%9%0%a%b%c%d%e%f%g%h%i%j%k%l%m%n%o%p%q%r%s%t%u%v%w%x%y%", +"z%A%B%C%D%E%F%G%H%=$=$;$;$;$=$;$m$I%J%K%v@L%M%N%O%P%Q%R%S%T%U%V%W%X%Y%Z%`% &.&+&@&#&$&%&&&*&=&-&", +";&>&,&'&)&!&~&{&]&;$;$;$;$;$;$;$;$^&/&K%(&_&:&<&[&}&|&1&2&3&4&5&6&7&8&9&0&a&b&c&d&e&f&g&h&i&j&k&", +"l&m&n&o&p&q&=.r&s&t&t&r$;$;$m$;$r$u&v&w&x&t$y&z&A&B&x@C&D&E&F&G&H&I&J&K&L&M&N&O&P&Q&R&S&T&U&V& ", +"W&X&Y&Z&`& *.*+*@*#*$*%*&***=*A@-*;*>*,*'*)*!*~*{*]*^*/*(*_*:*<*[*}*|*1* 2* ", +" 3*4*5*6*7*8*9*0*a*b*c*d*e*f*g*h*z@i*j*k*l*m*n*8%o*p*q*r* ", +" s*t*u*v*w*x*y*z*A*B*C*D*E*F*G*H*I*J*K*L*M*N*O*P*Q*R*S* ", +" T*U*V*W*X*Y*Z*`* =.=+=@=#=$=%=&=*===-=;=>=,='=)=!= ", +" ~={=]=^=/=(=_=:=<=n*[=}=|=1=2=3=4=5=6=7=8=9= ", +" 0=a=b=c=d=e=f=g=o%h=i=j=k=l=m=n=o=p=q=r= ", +" s=t=u=v=w=x=y=z=A=B=C=D=E=F=G=H= ", +" I=J=K=L=M=N=O=P=Q=R=S=T=U=V= ", +" W=X=Y=Z=`= -.-+-@- ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/data/mac/flarq.icns b/data/mac/flarq.icns new file mode 100644 index 0000000000000000000000000000000000000000..996d622fac73863320d223057f63e855b3734a7f GIT binary patch literal 40835 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%0D6y$hT`H=Ugf+ir{)<&+35*P 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 AbN~PV literal 0 HcmV?d00001 diff --git a/data/win32/flarq.ico b/data/win32/flarq.ico new file mode 100644 index 0000000000000000000000000000000000000000..a5f2c034d1f254591effbad53d82a2928d9e9044 GIT binary patch literal 12206 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 literal 0 HcmV?d00001 diff --git a/data/win32/fldigi.nsi b/data/win32/fldigi.nsi index f84bbf34..18da2e41 100644 --- a/data/win32/fldigi.nsi +++ b/data/win32/fldigi.nsi @@ -4,28 +4,59 @@ # Copyright (c) 2009 Stelios Bounanos, M0GLD. +# Variables +!define FLDIGI_DESCRIPTION "${FLDIGI_NAME} ${FLDIGI_VERSION}" +!define FLDIGI_STRING "${FLDIGI_NAME}-${FLDIGI_VERSION}" +!define FLARQ_DESCRIPTION "${FLARQ_NAME} ${FLARQ_VERSION}" +!define FLARQ_STRING "${FLARQ_NAME}-${FLARQ_VERSION}" +!ifdef HAVE_FLDIGI + !define PRODUCT_BINARY "${FLDIGI_BINARY}" + !define PRODUCT_NAME "${FLDIGI_NAME}" + !define PRODUCT_VERSION "${FLDIGI_VERSION}" + !define PRODUCT_STRING "${FLDIGI_STRING}" + !define PRODUCT_DESCRIPTION "${FLDIGI_DESCRIPTION}" +!else ifdef HAVE_FLARQ + !define PRODUCT_BINARY "${FLARQ_BINARY}" + !define PRODUCT_NAME "${FLARQ_NAME}" + !define PRODUCT_VERSION "${FLARQ_VERSION}" + !define PRODUCT_STRING "${FLARQ_STRING}" + !define PRODUCT_DESCRIPTION "${FLARQ_DESCRIPTION}" +!else + !error "Either HAVE_FLDIGI or HAVE_FLARQ must be defined" +!endif + # Compression options SetCompressor /SOLID lzma +# This function is called before displaying the first installer page. +# It aborts the installation if the Windows version is too old. +!include WinVer.nsh +Function .onInit + ${IfNot} ${AtLeastWin2000} + MessageBox MB_ICONSTOP "Sorry, your Windows version is too old.$\n${PRODUCT_NAME} requires Windows 2000 or later." + Abort + ${EndIf} +FunctionEnd + # The name of the installer -Name "${PROGRAM_NAME} ${PROGRAM_VERSION}" +Name "${PRODUCT_DESCRIPTION}" # The file to write OutFile ${INSTALLER_FILE} # The default installation directory -InstallDir $PROGRAMFILES\${PROGRAM_NAME}-${PROGRAM_VERSION} +InstallDir $PROGRAMFILES\${PRODUCT_STRING} # Registry key to check for directory (so if you install again, it will # overwrite the old one automatically) -!define INSTALL_DIR_REG_KEY SOFTWARE\${PROGRAM_NAME}-${PROGRAM_VERSION} +!define INSTALL_DIR_REG_KEY SOFTWARE\${PRODUCT_STRING} InstallDirRegKey HKLM "${INSTALL_DIR_REG_KEY}" "Install_Dir" # Request application privileges for Windows Vista RequestExecutionLevel admin # License -LicenseText "${PROGRAM_NAME} is distributed under the GNU GPL as detailed \ +LicenseText "${PRODUCT_NAME} is distributed under the GNU GPL as detailed \ below. You must abide by the terms of this license if you modify or \ redistribute the program." "Continue" LicenseData "${LICENSE_FILE}" @@ -34,10 +65,10 @@ SubCaption 0 ": License Information" # Other options BrandingText " " InstProgressFlags smooth -VIAddVersionKey ProductName "${PROGRAM_NAME}" -VIAddVersionKey ProductVersion "${PROGRAM_VERSION}" -VIAddVersionKey FileVersion "${PROGRAM_VERSION}" -VIAddVersionKey FileDescription "${PROGRAM_NAME} ${PROGRAM_VERSION} installer" +VIAddVersionKey ProductName "${PRODUCT_NAME}" +VIAddVersionKey ProductVersion "${PRODUCT_VERSION}" +VIAddVersionKey FileVersion "${PRODUCT_VERSION}" +VIAddVersionKey FileDescription "${FLDIGI_DESCRIPTION} installer" VIAddVersionKey LegalCopyright "Fldigi developers" VIAddVersionKey OriginalFilename "${INSTALLER_FILE}" VIProductVersion "3.0.0.0" @@ -53,50 +84,111 @@ UninstPage uninstConfirm UninstPage instfiles # Registry uninstall path -!define REG_UNINSTALL_PATH Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_NAME}-${PROGRAM_VERSION} +!define REG_UNINSTALL_PATH Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_STRING} -# The stuff to install -Section "${PROGRAM_NAME}" - SectionIn RO +# This is a hidden section and is always selected. It writes the uninstall +# registry keys and uninstaller binary. +Section -install # Set output path to the installation directory. SetOutPath $INSTDIR - # List files to be installed here - File "${BINARY}" - # Write the installation path into the registry + # Write the installation paths into the registry WriteRegStr HKLM "${INSTALL_DIR_REG_KEY}" "Install_Dir" "$INSTDIR" - # Write the uninstall keys for Windows - WriteRegStr HKLM "${REG_UNINSTALL_PATH}" "DisplayName" "${PROGRAM_NAME} ${PROGRAM_VERSION}" - WriteRegStr HKLM "${REG_UNINSTALL_PATH}" "DisplayVersion" "${PROGRAM_VERSION}" + WriteRegStr HKLM "${REG_UNINSTALL_PATH}" "DisplayName" "${PRODUCT_DESCRIPTION}" + WriteRegStr HKLM "${REG_UNINSTALL_PATH}" "DisplayVersion" "${PRODUCT_VERSION}" + WriteRegStr HKLM "${REG_UNINSTALL_PATH}" "DisplayIcon" '"$INSTDIR\${PRODUCT_BINARY}"' WriteRegStr HKLM "${REG_UNINSTALL_PATH}" "HelpLink" "${SUPPORT_URL}" WriteRegStr HKLM "${REG_UNINSTALL_PATH}" "Publisher" "Fldigi developers" WriteRegStr HKLM "${REG_UNINSTALL_PATH}" "URLUpdateInfo" "${UPDATES_URL}" WriteRegStr HKLM "${REG_UNINSTALL_PATH}" "UninstallString" '"$INSTDIR\uninstall.exe"' + WriteRegStr HKLM "${REG_UNINSTALL_PATH}" "QuietUninstallString" '"$INSTDIR\uninstall.exe" /S' WriteRegDWORD HKLM "${REG_UNINSTALL_PATH}" "NoModify" 1 WriteRegDWORD HKLM "${REG_UNINSTALL_PATH}" "NoRepair" 1 WriteUninstaller "uninstall.exe" SectionEnd +!ifdef HAVE_FLDIGI + Var WANT_FLDIGI +!endif +!ifdef HAVE_FLARQ + Var WANT_FLARQ +!endif + +# This section is present (and required) if the installer contains fldigi. +!ifdef HAVE_FLDIGI + Section "Fldigi" + SectionIn RO + SetOutPath $INSTDIR + File "${FLDIGI_BINARY}" + StrCpy $WANT_FLDIGI "true" + SectionEnd +!endif + +# This section is present if the installer contains flarq. It is optional if +# the installer also contains fldigi. +!ifdef HAVE_FLARQ + Section "Flarq" + !ifndef HAVE_FLDIGI + SectionIn RO + !endif + SetOutPath $INSTDIR + File "${FLARQ_BINARY}" + StrCpy $WANT_FLARQ "true" + SectionEnd +!endif + # Start Menu path -!define SM_PATH_BASE $SMPROGRAMS\${PROGRAM_NAME} -!define SM_PATH ${SM_PATH_BASE}\${PROGRAM_NAME}-${PROGRAM_VERSION} +!define SM_PATH_BASE $SMPROGRAMS\${PRODUCT_NAME} +!define SM_PATH ${SM_PATH_BASE}\${PRODUCT_STRING} # The following sections are optional Section "Start Menu Shortcuts" CreateDirectory "${SM_PATH}" - CreateShortCut "${SM_PATH}\${PROGRAM_NAME}.lnk" "$INSTDIR\${BINARY}" "" "$INSTDIR\${BINARY}" 0 - CreateShortCut "${SM_PATH}\Beginners' Guide.lnk" "${GUIDE_URL}" - CreateShortCut "${SM_PATH}\Documentation.lnk" "${DOCS_URL}" + !ifdef HAVE_FLDIGI + ${If} $WANT_FLDIGI == 'true' + CreateShortCut "${SM_PATH}\${FLDIGI_NAME}.lnk" "$INSTDIR\${FLDIGI_BINARY}" "" "$INSTDIR\${FLDIGI_BINARY}" 0 + CreateShortCut "${SM_PATH}\${FLDIGI_NAME} Beginners' Guide.lnk" "${GUIDE_URL}" + CreateShortCut "${SM_PATH}\${FLDIGI_NAME} Documentation.lnk" "${FLDIGI_DOCS_URL}" + ${EndIf} + !endif + !ifdef HAVE_FLARQ + ${If} $WANT_FLARQ == 'true' + CreateShortCut "${SM_PATH}\${FLARQ_NAME}.lnk" "$INSTDIR\${FLARQ_BINARY}" "" "$INSTDIR\${FLARQ_BINARY}" 0 + CreateShortCut "${SM_PATH}\${FLARQ_NAME} Documentation.lnk" "${FLARQ_DOCS_URL}" + ${EndIf} + !endif CreateShortCut "${SM_PATH}\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 SectionEnd -Section "Desktop Shortcut" - CreateShortCut "$DESKTOP\${PROGRAM_NAME} ${PROGRAM_VERSION}.lnk" "$INSTDIR\${BINARY}" "" "$INSTDIR\${BINARY}" 0 +Section "Desktop Shortcuts" + !ifdef HAVE_FLDIGI + ${If} $WANT_FLDIGI == 'true' + CreateShortCut "$DESKTOP\${FLDIGI_DESCRIPTION}.lnk" "$INSTDIR\${FLDIGI_BINARY}" "" \ + "$INSTDIR\${FLDIGI_BINARY}" 0 + ${EndIf} + !endif + !ifdef HAVE_FLARQ + ${If} $WANT_FLARQ == 'true' + CreateShortCut "$DESKTOP\${FLARQ_DESCRIPTION}.lnk" "$INSTDIR\${FLARQ_BINARY}" "" \ + "$INSTDIR\${FLARQ_BINARY}" 0 + ${EndIf} + !endif SectionEnd # This is unselected by default -Section /o "Quick Launch Shortcut" - CreateShortCut "$QUICKLAUNCH\${PROGRAM_NAME} ${PROGRAM_VERSION}.lnk" "$INSTDIR\${BINARY}" "" "$INSTDIR\${BINARY}" 0 +Section /o "Quick Launch Shortcuts" + !ifdef HAVE_FLDIGI + ${If} $WANT_FLDIGI == 'true' + CreateShortCut "$QUICKLAUNCH\${FLDIGI_DESCRIPTION}}.lnk" "$INSTDIR\${FLDIGI_BINARY}" "" \ + "$INSTDIR\${FLDIGI_BINARY}" 0 + ${EndIf} + !endif + !ifdef HAVE_FLARQ + ${If} $WANT_FLARQ == 'true' + CreateShortCut "$QUICKLAUNCH\${FLARQ_DESCRIPTION}.lnk" "$INSTDIR\${FLARQ_BINARY}" "" \ + "$INSTDIR\${FLARQ_BINARY}" 0 + ${EndIf} + !endif SectionEnd # Uninstaller @@ -106,16 +198,43 @@ Section "Uninstall" DeleteRegKey HKLM "${INSTALL_DIR_REG_KEY}" # Remove files and uninstaller - Delete $INSTDIR\${BINARY} - Delete $INSTDIR\uninstall.exe + !ifdef HAVE_FLDIGI + Delete /REBOOTOK $INSTDIR\${FLDIGI_BINARY} + !endif + !ifdef HAVE_FLARQ + Delete /REBOOTOK $INSTDIR\${FLARQ_BINARY} + !endif + Delete /REBOOTOK $INSTDIR\uninstall.exe # Remove shortcuts, if any Delete "${SM_PATH}\*.*" - Delete "$DESKTOP\${PROGRAM_NAME} ${PROGRAM_VERSION}.lnk" - Delete "$QUICKLAUNCH\${PROGRAM_NAME} ${PROGRAM_VERSION}.lnk" + !ifdef HAVE_FLDIGI + Delete "$DESKTOP\${FLDIGI_DESCRIPTION}.lnk" + Delete "$QUICKLAUNCH\${FLDIGI_DESCRIPTION}.lnk" + !endif + !ifdef HAVE_FLARQ + Delete "$DESKTOP\${FLARQ_DESCRIPTION}.lnk" + Delete "$QUICKLAUNCH\${FLARQ_DESCRIPTION}.lnk" + !endif # Remove directories used RMDir "${SM_PATH}" RMDir "${SM_PATH_BASE}" RMDir "$INSTDIR" SectionEnd + +# Offer to reboot the machine if the reboot flag is nonzero. This flag is set by +# commands that specify the /REBOOTOK switch if the BINARY_* files were in use +# during uninstallation. Stupid Windows. +Function un.onGUIEnd + IfRebootFlag 0 noreboot + MessageBox MB_YESNO|MB_ICONQUESTION \ + "A reboot is required to finish removing ${PRODUCT_NAME}. Do you wish to reboot now?" IDNO noreboot + Reboot + noreboot: +FunctionEnd + +# Tell the user if we could not reboot for some reason. +Function un.onRebootFailed + MessageBox MB_OK|MB_ICONSTOP "Reboot failed. Please reboot manually." /SD IDOK +FunctionEnd diff --git a/doc/Makefile.am b/doc/Makefile.am index 16d860a9..4dbd1a60 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,13 +1,23 @@ # Copyright (C) 2009 Stelios Bounanos, M0GLD (m0gld AT enotty DOT net) ASCIIDOC_CONF = asciidoc.conf -ASCIIDOC_SRC = fldigi.1.txt fldigi-shell.1.txt guide.txt -ASCIIDOC_MAN_DIST = fldigi.1 fldigi-shell.1 -ASCIIDOC_MAN_INST = fldigi.1 + +ASCIIDOC_SRC = fldigi.1.txt fldigi-shell.1.txt flarq.1.txt guide.txt +ASCIIDOC_MAN_DIST = fldigi.1 fldigi-shell.1 flarq.1 +ASCIIDOC_MAN_INST = +ASCIIDOC_HTML = + +if WANT_FLDIGI + ASCIIDOC_MAN_INST += fldigi.1 if ENABLE_XMLRPC - ASCIIDOC_MAN_INST += fldigi-shell.1 + ASCIIDOC_MAN_INST += fldigi-shell.1 +endif + ASCIIDOC_HTML += guide.html +endif + +if WANT_FLARQ + ASCIIDOC_MAN_INST += flarq.1 endif -ASCIIDOC_HTML = guide.html EXTRA_DIST = $(ASCIIDOC_CONF) $(ASCIIDOC_SRC) $(ASCIIDOC_MAN_DIST) diff --git a/doc/flarq.1.txt b/doc/flarq.1.txt new file mode 100644 index 00000000..99ad2286 --- /dev/null +++ b/doc/flarq.1.txt @@ -0,0 +1,147 @@ +FLARQ(1) +========= + + +== NAME == +flarq - ARQ data transfer utility for fldigi + + +== SYNOPSIS == +*flarq* ['OPTIONS'] + + +== DESCRIPTION == +*Flarq* (fast light automatic repeat request) is a file transfer application +that is based on the ARQ specification developed by Paul Schmidt, K9PS. It is +capable of transmitting and receiving frames of ARQ data via fldigi, as well as +MultiPSK on Windows. + + +== OPTIONS == +Long options begin with two hyphens and are handled by flarq. The option names +may be abbreviated to any unambiguous substring, and the option argument may be +separated from the name by a space or equals sign, as per +getopt(3)+. + +Short options begin with a single hyphen and are passed directly to FLTK. They +may be abbreviated only as indicated. + +*--arq-protocol* 'TYPE':: + Set the ARQ protocol. May be either ``fldigi'' or ``multipsk''. Defaults to + ``fldigi''. + +*--arq-server-address* 'HOSTNAME':: + Set the ARQ TCP server address. Defaults to ``127.0.0.1''. 'HOSTNAME' may be + any 'node name' string accepted by +getaddrinfo(3)+. + +*--arq-server-port* 'PORT':: + Set the ARQ TCP server port. Defaults to ``7322''. 'PORT' may be any 'service + name' string accepted by +getaddrinfo(3)+. + +*--debug*:: + Enable debugging messages. + +*--version*:: + Print version information and exit. + +*--build-info*:: + Print build information and exit. + +*--help*:: + Print options summary and exit. + +=== Standard FLTK options === +*-bg, -background* 'COLOUR':: + Set the background colour. + +*-bg2, -background2* 'COLOUR':: + Set the secondary (text) background colour. + +*-di, -display* 'DISPLAY':: + Specifies the X server to connect to; see +X(7)+. + +*-dn, -dnd* or *-nodn, -nodnd*:: + Enable or disable drag and drop copy and paste in text fields. + +*-fg, -foreground* 'COLOUR':: + Set the foreground colour. + +*-g, -geometry* 'GEOMETRY':: + Set the initial window size and position. *Flarq may not honour this option*. + +*-i, -iconic*:: + Start flarq in iconified state. *Flarq may not honour this option*. + +*-k, -kbd* or *-nok, -nokbd*:: + Enable or disable visible keyboard focus in non-text widgets. + +*-na, -name* 'CLASSNAME':: + Set the window class. Defaults to ``Flarq''. + +*-ti, -title* 'WINDOWTITLE':: + Set the window title. Defaults to ``flarq - ''. + +=== Additional UI options === +*--font* 'FONT[:SIZE]':: + Set the widget font and (optionally) size. Defaults to ``sans:12''. + + +== FILES == +$HOME/.flarq:: + The main settings file. + +The following directories are used to interface with MUAs such as Sylpheed: + +$HOME/Mail/ARQin:: + Stores incoming email messages. + +$HOME/Mail/ARQout:: + Stores outgoing email messages. + +$HOME/Mail/ARQsent:: + Stores sent email messages. + +The following directories are used for ARQ file transfer: + +$HOME/ARQrecv:: + Stores received files. + +$HOME/ARQsend:: + Stores files to be transmitted. + +$HOME/ARQfiles/logfile.txt:: + Stores transfer logs. + + +== BUGS == +* There are no command line arguments to override the default configuration file + and ARQ and Mail directories. + + +== SEE ALSO == +fldigi(1), getaddrinfo(3), getopt(3), X(7) + + +== RESOURCES == +Flarq web site: http://www.w1hkj.com/flarq_main.html + +Fldigi web site: http://www.w1hkj.com/Fldigi.html + +BerliOS project page: http://developer.berlios.de/projects/fldigi/ + +ARQ specification by Paul Schmidt, K9PS: http://www.w1hkj.com/FlarqHelpFiles/ARQ2.pdf + +== AUTHORS == +Flarq was written by David Freese, +W1HKJ+. + +This manual page was written by Stelios Bounanos . + + +== COPYING == +License GPLv2+: GNU GPL version 2 or later. + +//////////////////////////////////////////////////////////////////////////////// +// Emacs settings +// Local Variables: +// mode: doc +// End: +//////////////////////////////////////////////////////////////////////////////// diff --git a/m4/build.m4 b/m4/build.m4 index f7ff44a5..9cab09b4 100644 --- a/m4/build.m4 +++ b/m4/build.m4 @@ -3,27 +3,50 @@ AC_DEFUN([AC_FLDIGI_SH_DQ], [ ]) AC_DEFUN([AC_FLDIGI_BUILD_INFO], [ -# define build flags and substitute in Makefile.in - BUILD_CPPFLAGS="$BUILD_CPPFLAGS -I\$(srcdir) -I\$(srcdir)/include -I\$(srcdir)/irrxml \ +# Define build flags and substitute in Makefile.in +# CPPFLAGS + FLDIGI_BUILD_CPPFLAGS="-I\$(srcdir) -I\$(srcdir)/include -I\$(srcdir)/irrxml \ -I\$(srcdir)/fileselector $BOOST_CPPFLAGS" - AC_SUBST([BUILD_CPPFLAGS]) - - BUILD_CXXFLAGS="$PORTAUDIO_CFLAGS $FLTK_CFLAGS $SNDFILE_CFLAGS $SAMPLERATE_CFLAGS \ +# CXXFLAGS + FLDIGI_BUILD_CXXFLAGS="$PORTAUDIO_CFLAGS $FLTK_CFLAGS $SNDFILE_CFLAGS $SAMPLERATE_CFLAGS \ $PULSEAUDIO_CFLAGS $HAMLIB_CFLAGS $PNG_CFLAGS $XMLRPC_CFLAGS $MAC_UNIVERSAL_CFLAGS \ $INTL_CFLAGS $PTW32_CFLAGS $BFD_CFLAGS -pipe -Wall -fexceptions $OPT_CFLAGS $DEBUG_CFLAGS" - BUILD_LDFLAGS="$MAC_UNIVERSAL_LDFLAGS" - if test "x$ac_cv_debug" = "xyes"; then - BUILD_CXXFLAGS="$BUILD_CXXFLAGS -UNDEBUG" - BUILD_LDFLAGS="$BUILD_LDFLAGS $RDYNAMIC" - else - BUILD_CXXFLAGS="$BUILD_CXXFLAGS -DNDEBUG" - fi - AC_SUBST([BUILD_CXXFLAGS]) - AC_SUBST([BUILD_LDFLAGS]) - - BUILD_LDADD="$PORTAUDIO_LIBS $BOOST_LDFLAGS $FLTK_LIBS $SNDFILE_LIBS $SAMPLERATE_LIBS \ +# LDFLAGS + FLDIGI_BUILD_LDFLAGS="$MAC_UNIVERSAL_LDFLAGS" +# LDADD + FLDIGI_BUILD_LDADD="$PORTAUDIO_LIBS $BOOST_LDFLAGS $FLTK_LIBS $SNDFILE_LIBS $SAMPLERATE_LIBS \ $PULSEAUDIO_LIBS $HAMLIB_LIBS $PNG_LIBS $XMLRPC_LIBS $INTL_LIBS $PTW32_LIBS $BFD_LIBS $EXTRA_LIBS" - AC_SUBST([BUILD_LDADD]) + +# CPPFLAGS + FLARQ_BUILD_CPPFLAGS="-I\$(srcdir) -I\$(srcdir)/include -I\$(srcdir)/fileselector \ +-I\$(srcdir)/flarq-src -I\$(srcdir)/flarq-src/include $BOOST_CPPFLAGS" +# CXXFLAGS + FLARQ_BUILD_CXXFLAGS="$FLTK_CFLAGS $MAC_UNIVERSAL_CFLAGS $INTL_CFLAGS $PTW32_CFLAGS $BFD_CFLAGS \ +-pipe -Wall -fexceptions $OPT_CFLAGS $DEBUG_CFLAGS" +# LDFLAGS + FLARQ_BUILD_LDFLAGS="$MAC_UNIVERSAL_LDFLAGS" +# LDADD + FLARQ_BUILD_LDADD="$BOOST_LDFLAGS $FLTK_LIBS $INTL_LIBS $PTW32_LIBS $BFD_LIBS $EXTRA_LIBS" + + if test "x$ac_cv_debug" = "xyes"; then + FLDIGI_BUILD_CXXFLAGS="$FLDIGI_BUILD_CXXFLAGS -UNDEBUG" + FLDIGI_BUILD_LDFLAGS="$FLDIGI_BUILD_LDFLAGS $RDYNAMIC" + FLARQ_BUILD_CXXFLAGS="$FLARQ_BUILD_CXXFLAGS -UNDEBUG" + FLARQ_BUILD_LDFLAGS="$FLARQ_BUILD_LDFLAGS $RDYNAMIC" + else + FLDIGI_BUILD_CXXFLAGS="$FLDIGI_BUILD_CXXFLAGS -DNDEBUG" + FLARQ_BUILD_CXXFLAGS="$FLARQ_BUILD_CXXFLAGS -DNDEBUG" + fi + + AC_SUBST([FLDIGI_BUILD_CPPFLAGS]) + AC_SUBST([FLDIGI_BUILD_CXXFLAGS]) + AC_SUBST([FLDIGI_BUILD_LDFLAGS]) + AC_SUBST([FLDIGI_BUILD_LDADD]) + + AC_SUBST([FLARQ_BUILD_CPPFLAGS]) + AC_SUBST([FLARQ_BUILD_CXXFLAGS]) + AC_SUBST([FLARQ_BUILD_LDFLAGS]) + AC_SUBST([FLARQ_BUILD_LDADD]) #define build variables for config.h AC_DEFINE_UNQUOTED([BUILD_BUILD_PLATFORM], ["$build"], [Build platform]) @@ -49,11 +72,15 @@ $PULSEAUDIO_LIBS $HAMLIB_LIBS $PNG_LIBS $XMLRPC_LIBS $INTL_LIBS $PTW32_LIBS $BFD AC_FLDIGI_SH_DQ([$CXX -v 2>&1 | tail -1]) AC_DEFINE_UNQUOTED([BUILD_COMPILER], [$ac_sh_dq], [Compiler]) - AC_FLDIGI_SH_DQ([echo $BUILD_CPPFLAGS $BUILD_CXXFLAGS]) - AC_DEFINE_UNQUOTED([BUILD_CXXFLAGS], [$ac_sh_dq], [Compiler flags]) + AC_FLDIGI_SH_DQ([echo $FLDIGI_BUILD_CPPFLAGS $FLDIGI_BUILD_CXXFLAGS]) + AC_DEFINE_UNQUOTED([FLDIGI_BUILD_CXXFLAGS], [$ac_sh_dq], [Fldigi compiler flags]) + AC_FLDIGI_SH_DQ([echo $FLDIGI_BUILD_LDFLAGS $FLDIGI_BUILD_LDADD]) + AC_DEFINE_UNQUOTED([FLDIGI_BUILD_LDFLAGS], [$ac_sh_dq], [Fldigi linker flags]) - AC_FLDIGI_SH_DQ([echo $BUILD_LDFLAGS $BUILD_LDADD]) - AC_DEFINE_UNQUOTED([BUILD_LDFLAGS], [$ac_sh_dq], [Linker flags]) + AC_FLDIGI_SH_DQ([echo $FLARQ_BUILD_CPPFLAGS $FLARQ_BUILD_CXXFLAGS]) + AC_DEFINE_UNQUOTED([FLARQ_BUILD_CXXFLAGS], [$ac_sh_dq], [Flarq compiler flags]) + AC_FLDIGI_SH_DQ([echo $FLARQ_BUILD_LDFLAGS $FLARQ_BUILD_LDADD]) + AC_DEFINE_UNQUOTED([FLARQ_BUILD_LDFLAGS], [$ac_sh_dq], [Flarq linker flags]) if test "x$LC_ALL_saved" != "x"; then LC_ALL="$LC_ALL_saved" diff --git a/m4/progs.m4 b/m4/progs.m4 new file mode 100644 index 00000000..7a22f0be --- /dev/null +++ b/m4/progs.m4 @@ -0,0 +1,21 @@ +AC_DEFUN([AC_FLDIGI_PROGRAMS], [ + AC_ARG_ENABLE([fldigi], + AC_HELP_STRING([--disable-fldigi], [do not build fldigi]), + [case "${enableval}" in + yes|no) ac_cv_want_fldigi="${enableval}" ;; + *) AC_MSG_ERROR([bad value ${enableval} for --disable-fldigi]) ;; + esac], + [ac_cv_want_fldigi=yes]) + + AM_CONDITIONAL([WANT_FLDIGI], [test "x$ac_cv_want_fldigi" = "xyes"]) + + AC_ARG_ENABLE([flarq], + AC_HELP_STRING([--disable-flarq], [do not build flarq]), + [case "${enableval}" in + yes|no) ac_cv_want_flarq="${enableval}" ;; + *) AC_MSG_ERROR([bad value ${enableval} for --disable-flarq]) ;; + esac], + [ac_cv_want_flarq=yes]) + + AM_CONDITIONAL([WANT_FLARQ], [test "x$ac_cv_want_flarq" = "xyes"]) +]) diff --git a/scripts/mkappbundle.sh b/scripts/mkappbundle.sh index 0016f888..d6a7a2e7 100755 --- a/scripts/mkappbundle.sh +++ b/scripts/mkappbundle.sh @@ -3,9 +3,10 @@ ### Script to create the .app structure for osx ### 20080227 Stelios Bounanos M0GLD ### Updated 20080727: enable the .icns support +### Updated 20090525: add flarq -if [ $# -ne 4 ]; then - echo "Syntax: $0 data-dir build-dir bundle-dir static-bundle-dir" >&2 +if [ $# -ne 2 ]; then + echo "Syntax: $0 data-dir build-dir" >&2 exit 1 fi @@ -17,8 +18,8 @@ fi PWD=`pwd` data="${PWD}/$1" build="${PWD}/$2" -bundle_dir="$3" -static_bundle_dir="$4" +bundle_dir="$APPBUNDLE_NOLIBS" +static_bundle_dir="$APPBUNDLE" # more sanity checks for d in "$data" "$build"; do test -d "$d" && continue @@ -31,8 +32,9 @@ if ! test -w "$build"; then fi plist="${data}/mac/Info.plist.in" -icon="${data}/mac/fldigi.icns" -for f in "$plist" "$icon"; do +fldigi_icon="${data}/mac/fldigi.icns" +flarq_icon="${data}/mac/flarq.icns" +for f in "$plist" "$fldigi_icon" "$flarq_icon"; do test -r "$f" && continue echo "E: ${f}: not readable" >&2 exit 1 @@ -44,67 +46,91 @@ upcase1() sed 'h; s/\(^.\).*/\1/; y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/; G; s/\n.//' } -identifier="com.w1hkj.$PACKAGE_TARNAME" -name=$(echo "$PACKAGE_TARNAME" | upcase1) -# we'll use the first four consonants as the signature -signature="$(echo $PACKAGE_TARNAME | sed 's/[aeiouAEIOU]//g; s/\(^....\).*/\1/')" -binary="$PACKAGE_TARNAME" -version="${FLDIGI_VERSION_MAJOR}.${FLDIGI_VERSION_MINOR}" +function copy_libs() +{ + list="$1" + while test "x$list" != "x"; do + change="$list" + list="" + + for obj in $change; do + for lib in `otool -L $obj | \ + sed -n 's!^.*[[:space:]]\([^[:space:]]*\.dylib\).*$!\1!p' | \ + grep -Ev '^/(usr/lib|System)'`; do + libfn="`basename $lib`" + if ! test -f "Frameworks/$libfn"; then + cp "$lib" "Frameworks/$libfn" + install_name_tool -id "@executable_path/../Frameworks/$libfn" "Frameworks/$libfn" + list="$list Frameworks/$libfn" + fi + install_name_tool -change "$lib" "@executable_path/../Frameworks/$libfn" "$obj" + done + done + done +} + +function bundle() +{ + appname="${binary}-${appversion}.app" + cd "$build" + + # bundle the binary + echo "creating ${build}/$bundle_dir/$appname" + $mkinstalldirs "$bundle_dir/$appname/Contents/MacOS" "$bundle_dir/$appname/Contents/Resources" + cd "$bundle_dir" + $INSTALL_PROGRAM "${build}/$binary" "$appname/Contents/MacOS" + test "x$NOSTRIP" = "x" && ${STRIP:-strip} -S "$appname/Contents/MacOS/$binary" + + $INSTALL_DATA "$icon" "$appname/Contents/Resources" + echo "APPL${signature}" > "$appname/Contents/PkgInfo" + sed -e "s!%%IDENTIFIER%%!${identifier}!g; s!%%NAME%%!${name}!g;\ + s!%%SIGNATURE%%!${signature}!g; s!%%BINARY%%!${binary}!g;\ + s!%%VERSION%%!${version}!g; s!%%ICON%%!${icon##*/}!g;" < "$plist" > "$appname/Contents/Info.plist" + if grep '%%[A-Z]*%%' "$appname/Contents/Info.plist"; then + echo "E: unsubstituted variables in $appname/Contents/Info.plist" >&2 + exit 1 + fi + + + # bundle the binary and its non-standard dependencies + echo "creating ${build}/$static_bundle_dir/$appname" + cd .. + $mkinstalldirs "$static_bundle_dir" + cp -pR "$bundle_dir/$appname" "$static_bundle_dir" + $mkinstalldirs "$static_bundle_dir/$appname/Contents/Frameworks" + cd "$static_bundle_dir/$appname/Contents" + copy_libs "MacOS/$binary" +} set -e -cd "$build" +if test "x$WANT_FLDIGI" = "xyes"; then + identifier="com.w1hkj.$PACKAGE_TARNAME" + name=$(echo "$PACKAGE_TARNAME" | upcase1) + # we'll use the first four consonants as the signature + signature="$(echo $PACKAGE_TARNAME | sed 's/[aeiouAEIOU]//g; s/\(^....\).*/\1/')" + binary="$PACKAGE_TARNAME" + icon="$fldigi_icon" + version="${FLDIGI_VERSION_MAJOR}.${FLDIGI_VERSION_MINOR}" + appversion="$FLDIGI_VERSION" -# bundle the binary -appname="${PACKAGE_TARNAME}-${PACKAGE_VERSION}.app" -echo "creating ${build}/$bundle_dir/$appname" -$mkinstalldirs "$bundle_dir/$appname/Contents/MacOS" "$bundle_dir/$appname/Contents/Resources" -cd "$bundle_dir" -$INSTALL_PROGRAM "${build}/$binary" "$appname/Contents/MacOS" -if test "x$STRIP" != "x0"; then - strip -S "$appname/Contents/MacOS/$binary" -fi -$INSTALL_DATA "$icon" "$appname/Contents/Resources" -echo "APPL${signature}" > "$appname/Contents/PkgInfo" -sed -e "s!%%IDENTIFIER%%!${identifier}!g; s!%%NAME%%!${name}!g;\ - s!%%SIGNATURE%%!${signature}!g; s!%%BINARY%%!${binary}!g;\ - s!%%VERSION%%!${version}!g; s!%%ICON%%!${icon##*/}!g;" < "$plist" > "$appname/Contents/Info.plist" -if grep '%%[A-Z]*%%' "$appname/Contents/Info.plist"; then - echo "E: unsubstituted variables in $appname/Contents/Info.plist" >&2 - exit 1 + bundle fi +if test "x$WANT_FLARQ" = "xyes"; then + identifier="com.w1hkj.flarq" + name="Flarq" + signature="flrq" + binary="flarq" + icon="$flarq_icon" + version="${FLARQ_VERSION_MAJOR}.${FLARQ_VERSION_MINOR}" + appversion="$FLARQ_VERSION" -# bundle the binary and its non-standard dependencies -echo "creating ${build}/$static_bundle_dir/$appname" -cd .. -$mkinstalldirs "$static_bundle_dir" -cp -pR "$bundle_dir/$appname" "$static_bundle_dir" -$mkinstalldirs "$static_bundle_dir/$appname/Contents/Frameworks" -cd "$static_bundle_dir/$appname/Contents" - -list="MacOS/$binary" -while test "x$list" != "x"; do - change="$list" - list="" - - for obj in $change; do - for lib in `otool -L $obj | \ - sed -n 's!^.*[[:space:]]\([^[:space:]]*\.dylib\).*$!\1!p' | \ - grep -Ev '^/(usr/lib|System)'`; do - libfn="`basename $lib`" - if ! test -f "Frameworks/$libfn"; then - cp "$lib" "Frameworks/$libfn" - install_name_tool -id "@executable_path/../Frameworks/$libfn" "Frameworks/$libfn" - list="$list Frameworks/$libfn" - fi - install_name_tool -change "$lib" "@executable_path/../Frameworks/$libfn" "$obj" - done - done -done + bundle +fi cd "$build" echo $ECHO_N "creating disk image" -hdiutil create -ov -srcfolder "$bundle_dir" -format UDZO -tgtimagekey zlib-level=9 "$PACKAGE_TARNAME-$PACKAGE_VERSION-nolibs.dmg" +hdiutil create -ov -srcfolder "$bundle_dir" -format UDZO -tgtimagekey zlib-level=9 "${APPBUNDLE}-nolibs.dmg" echo $ECHO_N "creating disk image" -hdiutil create -ov -srcfolder "$static_bundle_dir" -format UDZO -tgtimagekey zlib-level=9 "$PACKAGE_TARNAME-$PACKAGE_VERSION.dmg" +hdiutil create -ov -srcfolder "$static_bundle_dir" -format UDZO -tgtimagekey zlib-level=9 "${APPBUNDLE}.dmg" diff --git a/scripts/mkhamlibstatic.sh b/scripts/mkhamlibstatic.sh index 2ce2bb7e..d4b105c6 100755 --- a/scripts/mkhamlibstatic.sh +++ b/scripts/mkhamlibstatic.sh @@ -42,4 +42,4 @@ case "$target_os" in ;; esac -$CXX -o ${1}${EXEEXT} $AM_CXXFLAGS $CXXFLAGS $AM_LDFLAGS $LDFLAGS $fldigi_OBJECTS $fldigi_LDADD +$CXX -o ${1}${EXEEXT} $AM_CXXFLAGS $fldigi_CXXFLAGS $CXXFLAGS $AM_LDFLAGS $fldigi_LDFLAGS $LDFLAGS $fldigi_OBJECTS $fldigi_LDADD diff --git a/scripts/mknsisinst.sh b/scripts/mknsisinst.sh index c33f153f..5c96a446 100755 --- a/scripts/mknsisinst.sh +++ b/scripts/mknsisinst.sh @@ -4,8 +4,8 @@ ### 20090510 Stelios Bounanos M0GLD -if [ $# -ne 3 ]; then - echo "Syntax: $0 data-dir build-dir installer-file" >&2 +if [ $# -ne 2 ]; then + echo "Syntax: $0 data-dir build-dir" >&2 exit 1 fi @@ -17,7 +17,6 @@ fi PWD=`pwd` data="${PWD}/$1" build="${PWD}/$2" -installer_file="$3" # more sanity checks for d in "$data" "$build"; do @@ -30,20 +29,26 @@ if ! test -w "$build"; then exit 1 fi -# aaaaaaaaaargh => Aaaaaaaaaargh -upcase1() -{ - sed 'h; s/\(^.\).*/\1/; y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/; G; s/\n.//' -} +set -e -binary="$PACKAGE_TARNAME".exe -if test "x$STRIP" != "x0"; then - $STRIP -S "$binary" +fldigi_name=Fldigi +fldigi_bin=fldigi.exe +flarq_name=Flarq +flarq_bin=flarq.exe + +if test "x$WANT_FLDIGI" != "xyes" && test "x$WANT_FLARQ" != "xyes"; then + echo "E: refusing to create empty installer" >&2 + exit 1 +fi +if test "x$WANT_FLDIGI" = "xyes"; then + test "x$NOSTRIP" = "x" && $STRIP -S "$fldigi_bin" + def="$def -DHAVE_FLDIGI -DFLDIGI_NAME=$fldigi_name -DFLDIGI_BINARY=$fldigi_bin -DFLDIGI_VERSION=$PACKAGE_VERSION" +fi +if test "x$WANT_FLARQ" = "xyes"; then + test "x$NOSTRIP" = "x" && $STRIP -S "$flarq_bin" + def="$def -DHAVE_FLARQ -DFLARQ_NAME=$flarq_name -DFLARQ_BINARY=$flarq_bin -DFLARQ_VERSION=$FLARQ_VERSION" fi -name="$(echo $PACKAGE_TARNAME | upcase1)" - -$MAKENSIS -V2 -NOCD -D"INSTALLER_FILE=$installer_file" -D"LICENSE_FILE=$data/../COPYING" \ - -D"PROGRAM_NAME=$name" -D"PROGRAM_VERSION=$PACKAGE_VERSION" \ - -D"BINARY=$binary" -D"SUPPORT_URL=$PACKAGE_HOME" -D"UPDATES_URL=$PACKAGE_DL" \ - -D"DOCS_URL=$PACKAGE_DOCS" -D"GUIDE_URL=$PACKAGE_GUIDE" "$data/win32/fldigi.nsi" +$MAKENSIS -V2 -NOCD -D"INSTALLER_FILE=$INSTALLER_FILE" -D"LICENSE_FILE=$data/../COPYING" \ + -D"SUPPORT_URL=$PACKAGE_HOME" -D"UPDATES_URL=$PACKAGE_DL" -D"FLDIGI_DOCS_URL=$PACKAGE_DOCS" \ + -D"FLARQ_DOCS_URL=$FLARQ_DOCS" -D"GUIDE_URL=$PACKAGE_GUIDE" $def "$data/win32/fldigi.nsi" diff --git a/scripts/tests/config-h.sh b/scripts/tests/config-h.sh index e007cb39..f395ade0 100755 --- a/scripts/tests/config-h.sh +++ b/scripts/tests/config-h.sh @@ -3,10 +3,11 @@ # Check for translation units that don't include config.h r=0 -for f in $fldigi_SOURCES; do +for f in $fldigi_SOURCES $flarq_SOURCES; do base=$(echo $f | sed -n '/\.[cC][cCpPxX]\{1,\}/ { s!.*/\(.*\)\.[^.]*$!\1!; p }') - if test "x$base" != "x" && test -f "${base}.${OBJEXT}" && \ - ! grep "include.*config\.h" "${srcdir}/${f}" >/dev/null; then + test "x$base" = "x" && continue + test -f "fldigi-${base}.${OBJEXT}" || test -f "flarq-${base}.${OBJEXT}" || continue + if ! grep "include.*config\.h" "${srcdir}/${f}" >/dev/null; then echo "E: $f does not include config.h" >&2 r=1 fi diff --git a/scripts/tests/cr.sh b/scripts/tests/cr.sh index 5fbd7385..033b46b3 100755 --- a/scripts/tests/cr.sh +++ b/scripts/tests/cr.sh @@ -3,7 +3,7 @@ # Check for files with CRLF line terminators r=0 -for f in $fldigi_SOURCES $EXTRA_fldigi_SOURCES $EXTRA_DIST; do +for f in $fldigi_SOURCES $flarq_SOURCES $EXTRA_fldigi_SOURCES $EXTRA_DIST; do base=$(echo $f | sed -n '/\.[cC][cCpPxX]\{1,\}/ { s!.*/\(.*\)\.[^.]*$!\1!; p }') if test "x$base" != "x" && grep " " "${srcdir}/${f}" >/dev/null; then echo "E: $f has CRLF line terminators" >&2 diff --git a/src/Makefile.am b/src/Makefile.am index a7bf2589..a91659cc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,18 +1,32 @@ # Copyright (C) 2007-2009 Stelios Bounanos, M0GLD (m0gld AT enotty DOT net) # Copyright (c) 2008 Dave Freese, W1HKJ (w1hkj AT w1hkj DOT com) -bin_PROGRAMS = fldigi +bin_PROGRAMS = +if WANT_FLDIGI + bin_PROGRAMS += fldigi +endif +if WANT_FLARQ + bin_PROGRAMS += flarq +endif # The BUILD_* variables are defined in build.m4 -AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" @BUILD_CPPFLAGS@ -AM_CXXFLAGS = @BUILD_CXXFLAGS@ -AM_CFLAGS = $(AM_CXXFLAGS) -AM_LDFLAGS = @BUILD_LDFLAGS@ -LDADD = @BUILD_LDADD@ +fldigi_CPPFLAGS = -DBUILD_FLDIGI -DLOCALEDIR=\"$(localedir)\" @FLDIGI_BUILD_CPPFLAGS@ +fldigi_CXXFLAGS = @FLDIGI_BUILD_CXXFLAGS@ +fldigi_CFLAGS = $(fldigi_CXXFLAGS) +fldigi_LDFLAGS = @FLDIGI_BUILD_LDFLAGS@ +fldigi_LDADD = @FLDIGI_BUILD_LDADD@ + +flarq_CPPFLAGS = -DBUILD_FLARQ -DLOCALEDIR=\"$(localedir)\" @FLARQ_BUILD_CPPFLAGS@ +flarq_CXXFLAGS = @FLARQ_BUILD_CXXFLAGS@ +flarq_CFLAGS = $(flarq_CXXFLAGS) +flarq_LDFLAGS = @FLARQ_BUILD_LDFLAGS@ +flarq_LDADD = @FLARQ_BUILD_LDADD@ + HAMLIB_SRC = include/hamlib.h rigcontrol/hamlib.cxx include/rigclass.h rigcontrol/rigclass.cxx XMLRPC_SRC = include/xmlrpc.h misc/xmlrpc.cxx -WIN32_RES_SRC = fldigirc.rc +FLDIGI_WIN32_RES_SRC = fldigirc.rc +FLARQ_WIN32_RES_SRC = flarq-src/flarqrc.rc LOCATOR_SRC = misc/locator.c BENCHMARK_SRC = include/benchmark.h misc/benchmark.cxx REGEX_SRC = compat/regex.h compat/regex.c @@ -23,8 +37,10 @@ NLS_SRC = misc/nls.cxx # We distribute these but do not always compile them EXTRA_fldigi_SOURCES = $(HAMLIB_SRC) $(XMLRPC_SRC) $(WIN32_RES_SRC) $(LOCATOR_SRC) \ $(BENCHMARK_SRC) $(REGEX_SRC) $(STACK_SRC) $(MINGW32_SRC) $(NLS_SRC) +EXTRA_flarq_SOURCES = $(FLARQ_WIN32_RES_SRC) fldigi_SOURCES = +flarq_SOURCES = if ENABLE_HAMLIB fldigi_SOURCES += $(HAMLIB_SRC) @@ -43,18 +59,22 @@ endif if COMPAT_REGEX fldigi_SOURCES += $(REGEX_SRC) + flarq_SOURCES += $(REGEX_SRC) endif if COMPAT_STACK fldigi_SOURCES += $(STACK_SRC) + flarq_SOURCES += $(STACK_SRC) endif if MINGW32 fldigi_SOURCES += $(MINGW32_SRC) + flarq_SOURCES += $(MINGW32_SRC) endif if USE_NLS fldigi_SOURCES += $(NLS_SRC) + flarq_SOURCES += $(NLS_SRC) endif ######################################################################## @@ -63,6 +83,12 @@ endif FLDIGI_VERSION_MAJOR = @FLDIGI_VERSION_MAJOR@ FLDIGI_VERSION_MINOR = @FLDIGI_VERSION_MINOR@ FLDIGI_VERSION_PATCH = @FLDIGI_VERSION_PATCH@ +FLDIGI_VERSION = @FLDIGI_VERSION@ +FLARQ_VERSION_MAJOR = @FLARQ_VERSION_MAJOR@ +FLARQ_VERSION_MINOR = @FLARQ_VERSION_MINOR@ +FLARQ_VERSION_PATCH = @FLARQ_VERSION_PATCH@ +FLARQ_VERSION = @FLARQ_VERSION@ + .EXPORT_ALL_VARIABLES: appbundle nsisinst hamlib-static @@ -72,24 +98,29 @@ BUILT_SOURCES = nodist_fldigi_SOURCES = $(BUILT_SOURCES) # and deleted by the clean targets CLEANFILES = $(BUILT_SOURCES) +CLEAN_LOCAL = if WIN32 if HAVE_WINDRES .rc.o: $(WINDRES) -I$(srcdir)/include -I$(srcdir)/../data/win32 $< -O coff $@ -fldigi_SOURCES += $(WIN32_RES_SRC) +fldigi_SOURCES += $(FLDIGI_WIN32_RES_SRC) +flarq_SOURCES += $(FLARQ_WIN32_RES_SRC) endif endif install-exec-local: +if WANT_FLDIGI if ENABLE_XMLRPC if test -f $(srcdir)/../scripts/fldigi-shell; then \ $(mkinstalldirs) $(DESTDIR)/$(bindir); \ $(INSTALL_SCRIPT) $(srcdir)/../scripts/fldigi-shell $(DESTDIR)/$(bindir); \ fi endif +endif install-data-local: +if WANT_FLDIGI if test -f $(srcdir)/../data/fldigi.xpm; then \ $(mkinstalldirs) $(DESTDIR)/$(datadir)/pixmaps; \ $(INSTALL_DATA) $(srcdir)/../data/fldigi.xpm $(DESTDIR)/$(datadir)/pixmaps; \ @@ -98,42 +129,84 @@ install-data-local: $(mkinstalldirs) $(DESTDIR)/$(datadir)/applications; \ $(INSTALL_DATA) $(srcdir)/../data/fldigi.desktop $(DESTDIR)/$(datadir)/applications; \ fi +endif +if WANT_FLARQ + if test -f $(srcdir)/../data/flarq.xpm; then \ + $(mkinstalldirs) $(DESTDIR)/$(datadir)/pixmaps; \ + $(INSTALL_DATA) $(srcdir)/../data/flarq.xpm $(DESTDIR)/$(datadir)/pixmaps; \ + fi + if test -f $(srcdir)/../data/flarq.desktop; then \ + $(mkinstalldirs) $(DESTDIR)/$(datadir)/applications; \ + $(INSTALL_DATA) $(srcdir)/../data/flarq.desktop $(DESTDIR)/$(datadir)/applications; \ + fi +endif uninstall-local: +if WANT_FLDIGI rm -f $(DESTDIR)$(bindir)/fldigi-shell rm -f $(DESTDIR)/$(datadir)/pixmaps/fldigi.xpm rm -f $(DESTDIR)/$(datadir)/applications/fldigi.desktop +endif +if WANT_FLARQ + rm -f $(DESTDIR)/$(datadir)/pixmaps/flarq.xpm + rm -f $(DESTDIR)/$(datadir)/applications/flarq.desktop +endif + +FLDIGI_FL_SRC = dialogs/confdialog.fl dialogs/colorsfonts.fl rigcontrol/rigdialog.fl logbook/lgbook.fl +FLARQ_FL_SRC = flarq-src/arqdialogs.fl if HAVE_FLUID -flgen: $(srcdir)/dialogs/confdialog.fl $(srcdir)/dialogs/colorsfonts.fl $(srcdir)/rigcontrol/rigdialog.fl +flgen: $(FLDIGI_FL_SRC) $(FLARQ_FL_SRC) +if WANT_FLDIGI (cd $(srcdir)/include; \ - $(FLUID) -c -o ../dialogs/confdialog.cxx -h confdialog.h ../dialogs/confdialog.fl; \ - $(FLUID) -c -o ../dialogs/colorsfonts.cxx -h colorsfonts.h ../dialogs/colorsfonts.fl; \ - $(FLUID) -c -o ../rigcontrol/rigdialog.cxx -h rigdialog.h ../rigcontrol/rigdialog.fl; \ - $(FLUID) -c -o ../logbook/lgbook.cxx -h lgbook.h ../logbook/lgbook.fl) + for f in $(FLDIGI_FL_SRC); do \ + c=$${f%.fl}.cxx; h=$${f%.fl}.h; h=$${h##*/}; \ + $(FLUID) -c -o ../$$c -h $$h ../$$f; \ + done) +endif +if WANT_FLARQ + (cd $(srcdir)/flarq-src/include; \ + for f in $(FLARQ_FL_SRC); do \ + c=$${f%.fl}.cxx; h=$${f%.fl}.h; h=$${h##*/}; \ + $(FLUID) -c -o ../../$$c -h $$h ../../$$f; \ + done) +endif +endif + + +if WANT_FLDIGI + WANT_FLDIGI = yes + INSTALLER_FILE = $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)_setup.exe + APPBUNDLE=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION) + APPBUNDLE_NOLIBS=$(APPBUNDLE)-nolibs +endif +if WANT_FLARQ + WANT_FLARQ = yes +if !WANT_FLDIGI + INSTALLER_FILE = flarq-$(FLARQ_VERSION)_setup.exe + APPBUNDLE=flarq-$(FLARQ_VERSION) + APPBUNDLE_NOLIBS=$(APPBUNDLE)-nolibs +endif endif if DARWIN appbundle: $(bin_PROGRAMS) - sh $(srcdir)/../scripts/mkappbundle.sh "$(srcdir)/../data" . \ - $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-nolibs \ - $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) - CLEANFILES += $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-nolibs \ - $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) \ - $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)*.dmg + sh $(srcdir)/../scripts/mkappbundle.sh "$(srcdir)/../data" . + CLEAN_LOCAL += $(APPBUNDLE_NOLIBS) $(APPBUNDLE) $(APPBUNDLE)*.dmg endif if HAVE_NSIS nsisinst: $(bin_PROGRAMS) - sh $(srcdir)/../scripts/mknsisinst.sh "$(srcdir)/../data" . \ - $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)_setup.exe - CLEANFILES += $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)_setup.exe + sh $(srcdir)/../scripts/mknsisinst.sh "$(srcdir)/../data" . + CLEANFILES += $(INSTALLER_FILE) endif +if WANT_FLDIGI if ENABLE_HAMLIB hamlib-static: $(fldigi_OBJECTS) sh $(srcdir)/../scripts/mkhamlibstatic.sh fldigi endif +endif TESTS = $(srcdir)/../scripts/tests/config-h.sh $(srcdir)/../scripts/tests/cr.sh @@ -152,6 +225,8 @@ distclean-local: fi endif +clean-local: + -rm -rf $(CLEAN_LOCAL) # Sources that we build. It is OK to have headers here. fldigi_SOURCES += \ @@ -249,6 +324,7 @@ fldigi_SOURCES += \ include/dsp.h \ include/newinstall.h \ include/olivia.h \ + include/pkg.h \ include/picture.h \ include/progress.h \ include/psk.h \ @@ -433,6 +509,52 @@ EXTRA_fldigi_SOURCES += \ rsid/rsid_fft.h \ dialogs/guide.cxx +flarq_SOURCES += \ + dialogs/font_browser.cxx \ + flarq-src/arq.cxx \ + flarq-src/arqdialogs.cxx \ + flarq-src/arqhelp.cxx \ + flarq-src/b64.cxx \ + flarq-src/flarq.cxx \ + flarq-src/flarqenv.cxx \ + flarq-src/include/arq.h \ + flarq-src/include/arqdialogs.h \ + flarq-src/include/b64.h \ + flarq-src/include/flarq.h \ + flarq-src/include/flarqenv.h \ + include/Fl_Text_Display_mod.H \ + include/Fl_Text_Editor_mod.H \ + include/FTextView.h \ + include/debug.h \ + include/fileselect.h \ + include/flinput2.h \ + include/flmisc.h \ + include/font_browser.h \ + include/icons.h \ + include/pixmaps.h \ + include/re.h \ + include/socket.h \ + include/stacktrace.h \ + include/table.h \ + include/util.h \ + fileselector/FL/Fl_Native_File_Chooser.H \ + fileselector/Fl_Native_File_Chooser.cxx \ + fileselector/fileselect.cxx \ + logbook/table.cxx \ + misc/ascii.cxx \ + misc/debug.cxx \ + misc/stacktrace.cxx \ + widgets/flinput2.cxx \ + widgets/flmisc.cxx \ + misc/icons.cxx \ + misc/pixmaps.cxx \ + misc/re.cxx \ + misc/socket.cxx \ + misc/util.cxx \ + widgets/Fl_Text_Display_mod.cxx \ + widgets/Fl_Text_Editor_mod.cxx \ + widgets/FTextView.cxx + # Additional non-source files that we distribute EXTRA_DIST = \ $(srcdir)/../scripts/mkappbundle.sh \ @@ -447,7 +569,9 @@ EXTRA_DIST = \ $(srcdir)/../data/mac/Info.plist.in \ $(srcdir)/../data/mac/fldigi.icns \ $(srcdir)/../data/win32/fldigi.ico \ - dialogs/confdialog.fl \ - dialogs/colorsfonts.fl \ - rigcontrol/rigdialog.fl \ - logbook/lgbook.fl + $(srcdir)/../data/flarq.desktop \ + $(srcdir)/../data/flarq.xpm \ + $(srcdir)/../data/mac/flarq.icns \ + $(srcdir)/../data/win32/flarq.ico \ + $(FLDIGI_FL_SRC) \ + $(FLARQ_FL_SRC) diff --git a/src/flarq-src/arq.cxx b/src/flarq-src/arq.cxx new file mode 100644 index 00000000..6647a701 --- /dev/null +++ b/src/flarq-src/arq.cxx @@ -0,0 +1,1460 @@ +// arq module arq.cxx +// Copyright (c) 2007, Dave Freese, W1HKJ +// +// +// arq.cxx / arq.h is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// arq.cxx 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 your program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +#include + +#include + +#include + +#include "arq.h" + +using namespace std; + +//============================================================================= +// status messages +//============================================================================= +string TXPOLL = "TX: Send Blocks Report"; +string STIMEDOUT = "Timed out"; +string ABORTXFR = "ABORT transfer"; +string RXIDENT = "RX: Link Still Active"; +string RXCONREQ = "RX: Connect Request"; +string RXCONACK = "RX: Connect OK"; +string RXDISCONN = "RX: Disconnect Request"; +string RXDISCONACK = "RX: Disconnect OK"; +string RXSTATUS = "RX: Status Report"; +string RXPOLL = "RX: Send Blocks Report"; +string TXSTATUS = "TX: Blocks Received OK"; +string TXDISCONN = "TX: Disconnect Request"; +string TXDISACK = "TX: Disconnect OK"; +string TXBEACON = "TX: Beacon"; +string TXCONNECT = "TX: Connect"; +string TXCONNACK = "TX: Connect OK"; +string TXIDENT = "TX: Watchdog %d"; + +//bool bPoll = false; + +string arq::upcase(string s) +{ + for (size_t i = 0; i < s.length(); i++) + s[i] = toupper(s[i]); + return s; +} + +arq::arq() +{ + sendfnc = NULL; + rcvfnc = NULL; + printRX = NULL; + abortfnc = NULL; + disconnectfnc = NULL; + qualityfnc = NULL; + printRX_DEBUG = NULL; + printTX_DEBUG = NULL; + rxUrCall = NULL; + + Header.erase(); + + MyStreamID = '0'; + UrStreamID = '0'; + + UrCall.erase(); + MyCall.erase(); + + logfile = "server.log"; + +// queues // + TxTextQueue.clear();//erase(); // Text out to mail engine + RxTextQueue.clear();//erase(); // Text in from mail engine + TxPlainTextQueue.clear();//erase(); + RxFrameQueue.clear();//erase(); + lastRxChar = 0; + TXflag = false; + + Sessionnumber = 0; + + exponent = EXPONENT; + maxheaders = MAXHEADERS; + RetryTime = RETRYTIME; + Retries = RETRIES; + Timeout = TIMEOUT; + TxDelay = TXDELAY; + immediate = false; + primary = false; + + setBufferlength(); + + +// status variables // +// totalRx = 0; +// nbrbadRx = 0; + totalTx = 0; + nbrbadTx = 0; + payloadlength = 32; // Average length of payload received + +// static status + Firstsent = MAXCOUNT - 1; // First Header I sent last turn + LastHeader = MAXCOUNT - 1; // Last Header I sent last turn + Lastqueued = MAXCOUNT - 1; // Last Header in static send queue + + EndHeader = MAXCOUNT - 1; // Last I received o.k. + GoodHeader = MAXCOUNT - 1; // Last Header received consecutive + +// Ur status + UrGoodHeader = MAXCOUNT - 1; // Other station's Good Header + UrLastHeader = MAXCOUNT - 1; // Other station's Header last sent + UrEndHeader = MAXCOUNT - 1; // Other station's last received Header + blkcount = -1; + + TXflag = false; // TX on + LinkState = DOWN; // ARQ link is initially down + Sending = 0; + PollOK = false; +// bABORT = false; + + MyMissing.clear(); + MissingRxBlocks = ""; + + TxBlocks.clear(); + TxMissing.clear(); + TxPending.clear(); + + RxPending.clear(); + + arqstop = false; + + retries = baseRetries = Retries; + baseRetryTime = RetryTime; + baseTimeout = Timeout; + + retrytime = RetryTime / ARQLOOPTIME; + timeout = Timeout / ARQLOOPTIME; + loopcount = 0; + + tx2txdelay = 0;//TxDelay / ARQLOOPTIME; + +// srand(time(NULL)); +} + +void arq::setBufferlength() +{ + Bufferlength = 1; + for (int i = 0; i < exponent; i++) Bufferlength *= 2; + MyBlockLengthChar = '0' + exponent; +} + +void arq::resetTx() +{ + Firstsent = MAXCOUNT - 1; // First Header I sent last turn + LastHeader = MAXCOUNT - 1; // Last Header I sent last turn + Lastqueued = MAXCOUNT - 1; // Last Header in static send queue + TxMissing.clear(); + TxBlocks.clear(); + TxPending.clear(); + TxTextQueue.clear(); +// UrMissing.clear(); +} + +void arq::resetRx() +{ + RxTextQueue.clear();//erase(); // Text in from mail engine + RxFrameQueue.clear();//erase(); + lastRxChar = 0; + EndHeader = MAXCOUNT - 1; // Last I received o.k. + GoodHeader = MAXCOUNT - 1; // Last Header I received conseq. o.k, 1st in send queue + RxPending.clear(); + MissingRxBlocks = ""; +} + +void arq::reset() +{ + resetTx(); + resetRx(); + immediate = false; + primary = false; + blkcount = -1; +// bABORT = false; +} + +// new session number +// unknown stream id = 0 +// known id's from 1 to 63 +void arq::newsession() +{ + if (++SessionNumber == 64) SessionNumber = 1; + MyStreamID = SessionNumber + '0'; +} + +// get new blocknumber +void arq::newblocknumber() +{ + Lastqueued++; + Lastqueued %= MAXCOUNT; +} + +// Checksum of header + Header +string arq::checksum(string &s) +{ + framecrc.reset(); + return framecrc.scrc16(s); +} + +// Start header when MyStreamID has been assigned +void arq::newHeader() +{ + Header.erase(); + Header += SOH; + Header += '0'; // protocol version; +} + +void arq::IdHeader() +{ + newHeader(); + Header += UrStreamID; +} + +void arq::UnkHeader() +{ + newHeader(); + Header += '0'; +} + +char crlf[3] = " "; + +void arq::addToTxQue(string s) +{ +// TxTextQueue += "\r\n"; + crlf[0] = 0x0D; + crlf[1] = 0x0A; + TxTextQueue.append(s); + TxTextQueue.append(crlf); + totalTx++; +} + +// Connect (client:port, server:port) +// c Header = Client:port Server:port +// e.g.: '00cW1HKJ:1025 KH6TY:24 4' +// +void arq::connectFrame() +{ + char szGlobals[24]; + reset(); + UnkHeader(); + Header += CONREQ; + + Payload.erase(); + Payload.append(MyCall); + Payload.append(":1025"); + Payload += ' '; + Payload.append(UrCall); + Payload.append(":24"); + Payload += ' '; + Payload += MyStreamID; + Payload += ' '; + Payload += MyBlockLengthChar; + + snprintf(szGlobals, 23, " T%ldR%ldW%ld", Timeout/1000, Retries, RetryTime/1000); + Payload.append(szGlobals); + + Frame = Header + Payload; + + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); + + LinkState = CONNECTING; + printSTATUS(TXCONNECT, 5.0); +} + + +// Connect acknowledge (server:port, client:port) +// k Header = Server:port Client:port +// e.g: '00kKH6TY:24 W1HKJ:1024 8 6' +// +void arq::ackFrame () +{ + reset(); + IdHeader(); + Header += CONACK; + + Payload.erase(); + Payload.append(MyCall); + Payload.append(":24"); + Payload += ' '; + Payload.append(UrCall); + Payload += ' '; + Payload += MyStreamID; + Payload += ' '; + Payload += MyBlockLengthChar; + + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); + printSTATUS(TXCONNACK, 5.0); +} + +// Connect (caller:port, static:port) +// c Header = Caller:port static:port +// e.g.: '00cW1HKJ:87 KH6TY:87 4' +// +void arq::ttyconnectFrame() +{ + UnkHeader(); + Header += CONREQ; + + Payload.erase(); + Payload.append(MyCall); + Payload.append(":87"); + Payload += ' '; + Payload.append(UrCall); + Payload.append(":87"); + Payload += ' '; + Payload += MyStreamID; + Payload += ' '; + Payload += MyBlockLengthChar; + + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); +} + +// Connect acknowledge (server:port, client:port) +// k Header = Server:port Client:port +// e.g: '00kKH6TY:87 W1HKJ 4' +// Service id # 87 is keyboard-to-keyboard +// +void arq::ttyackFrame() +{ + IdHeader(); + Header += CONACK; + + Payload.erase(); + Payload.append(MyCall); + Payload.append(":87"); + Payload += ' '; + Payload.append(UrCall); + Payload += ' '; + Payload += MyBlockLengthChar; + + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); +} + +// Identify +//i frame = '00iKH6TY de W1HKJ' +void arq::identFrame() +{ + IdHeader(); + Header += IDENT; + + Payload.erase(); + Payload.append(UrCall); + Payload.append(" de "); + Payload.append(MyCall); + + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); + + char szIDENT[80]; + snprintf(szIDENT,sizeof(szIDENT), TXIDENT.c_str(), retries); + printSTATUS(szIDENT, 5.0); + +} + +// e.g. Ping frame +// u Header = From:port +// e.g: '00uKH6TY:7 ' +void arq::pingFrame() +{ + IdHeader(); + Header += _UNPROTO; + + Payload.erase(); + Payload.append(MyCall); + Payload.append(":7"); + Payload += ' '; + + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); +} + +// talk frame +// similar to UNPROTO frame +// but only sent if CONNECTED +void arq::talkFrame(string txt) +{ + IdHeader(); + Header += _TALK; + + Payload.erase(); + Payload.append(MyCall); + Payload.append(":73"); + Payload += ' '; + if (txt.length() > (size_t)Bufferlength) + Payload.append(txt.substr(0, Bufferlength)); + else + Payload.append(txt); + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); +} + +void arq::ackAbortFrame() +{ + IdHeader(); + Header += _ACKABORT; + + Payload.erase(); + Payload += (LastHeader + 0x20); + Payload += (GoodHeader + 0x20); + Payload += (EndHeader + 0x20); + Payload.append(MissingRxBlocks); + + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); + printSTATUS(TXSTATUS, 5.0); +} + +// Status report (End, Good, Lastrx, Missing) +//p frame = +//e.g.: '00sXHCAB' +// +void arq::statFrame() +{ + IdHeader(); + Header += STATUS; + + Payload.erase(); + Payload += (LastHeader + 0x20); + Payload += (GoodHeader + 0x20); + Payload += (EndHeader + 0x20); + Payload.append(MissingRxBlocks); + + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); + printSTATUS(TXSTATUS, 5.0); +} + +// Disconnect session +//d frame = "" +//e.g.: '00d' + +void arq::disconnectFrame() +{ + IdHeader(); + Header += DISREQ; + + Payload.erase(); + Payload.append(MyCall); + Payload.append(":90"); + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); + printSTATUS(TXDISCONN, 5.0); +} + +void arq::disackFrame() +{ + IdHeader(); + Header += _DISACK; + + Payload.erase(); + Payload.append(MyCall); + Payload.append(":91"); + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + addToTxQue(Frame); + printSTATUS(TXDISACK, 5.0); +} + +// ABORT session +//a frame = "" +//e.g.: '00a' +void arq::abortFrame() +{ + IdHeader(); + Header += _ABORT; + + Payload.erase(); + Payload.append(MyCall); + Payload.append(":92"); + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); +} + +// Beacon frame +// u Header = From:port data +// e.g: '00uKH6TY:72 Beacon text ' +// +void arq::beaconFrame(string txt) +{ + UnkHeader(); + Header += _UNPROTO; + + Payload.erase(); + Payload.append(MyCall); + Payload.append(":72"); + Payload += ' '; + if (txt.length() > (size_t)Bufferlength) + Payload.append(txt.substr(0, Bufferlength)); + else + Payload.append(txt); + Frame = Header + Payload; + Frame = Frame + checksum(Frame); + Frame += EOT; + + addToTxQue(Frame); + printSTATUS(TXBEACON, 5.0); +} + +// poll +//p frame = +//e.g.: '00pXHCAB' +void arq::pollFrame() +{ + + IdHeader(); + Frame = Header; + Frame += POLL; + Frame.append(MyCall); + Frame += SUB; + Frame += (LastHeader + 0x20); + Frame += (GoodHeader + 0x20); + Frame += (EndHeader + 0x20); + Frame.append(MissingRxBlocks); + Frame.append(checksum(Frame)); + Frame += EOT; + + addToTxQue(Frame); + printSTATUS(TXPOLL, 5.0); +} + +// Text frame +void arq::textFrame(cTxtBlk block) +{ + IdHeader(); + Frame = Header; + Frame += (block.nbr() + 0x20); + Frame.append(block.text()); + Frame.append(checksum(Frame)); + Frame += SOH; + + addToTxQue(Frame); +} + +//===================================================================== + +void arq::parseIDENT() +{ + timeout = Timeout / ARQLOOPTIME; + statFrame(); + immediate = true; + printSTATUS(RXIDENT, 5.0); +} + +void arq::parseCONREQ() +{ + + size_t p1 = 0, p2 = rcvPayload.find(':'); + if (p2 == string::npos) + return; +// if (LinkState == CONNECTED || LinkState == WAITFORACK) return; // disallow multiple connects + +// requesting stations callsign + UrCall = upcase(rcvPayload.substr(p1, p2 - p1)); + p1 = rcvPayload.find(' ', p2+1); + if (p1 == string::npos) { + UrCall.erase(); + return; + } + + p1++; + p2 = rcvPayload.find(":", p1); + string testcall = upcase(rcvPayload.substr(p1, p2 - p1)); + if (testcall != MyCall) { + UrCall.erase(); + return; + } + + p1 = rcvPayload.find(' ', p2 +1); + if (p1 == string::npos) { + UrCall.erase(); + return; + } + + p1++; // *p1 ==> StreamID for requesting station + UrStreamID = rcvPayload[p1]; + p1++; // *p1 ==> requested block size + UrBlockLengthChar = rcvPayload[p1]; + + p1 += 3; // *p1 ==>" TnnnRnnnWnnn" + if (p1 < rcvPayload.length()) { + char num[7]; + if (rcvPayload[p1] == 'T') { + int n = 0; + while (rcvPayload[++p1] != 'R' && n < 6) num[n++] = rcvPayload[p1]; + num[n] = 0; + sscanf(num, "%ld", &Timeout); + Timeout *= 1000; + if (p1 < rcvPayload.length() && rcvPayload[p1] == 'R') { + int n = 0; + while (rcvPayload[++p1] != 'W' && n < 6) num[n++] = rcvPayload[p1]; + num[n] = 0; + sscanf(num, "%ld", &Retries); + if (p1 < rcvPayload.length() && rcvPayload[p1] == 'W') { + int n = 0; + while (++p1 < rcvPayload.length() && n < 6) num[n++] = rcvPayload[p1]; + num[n] = 0; + sscanf(num, "%ld", &RetryTime); + RetryTime *= 1000; + Timeout += Retries * RetryTime; + } + } +/* + char line[80]; + string NewValues = "Temporary control parameters set to\n"; + snprintf(line, 79, " Retries = %ld\n", Retries); + NewValues.append(line); + snprintf(line, 79, " Wait time = %ld secs\n", RetryTime / 1000); + NewValues.append(line); + snprintf(line, 79, " Timeout = %ld secs\n", Timeout / 1000); + NewValues.append(line); + printRX(NewValues); +*/ + } + } + + reset(); + + LinkState = WAITFORACK; + newsession(); + + if (rxUrCall) rxUrCall(UrCall); + + TxTextQueue.clear();//erase(); + ackFrame(); + immediate = true; + printSTATUS(RXCONREQ, 5.0); + +} + +void arq::parseCONACK() +{ + if (LinkState < CONNECTING ) { //!= CONNECTING) { + return; // Connect Acknowledge only valid during a connect + } + + size_t p1 = 0, p2 = rcvPayload.find(':'); +// LinkState = DOWN; + if (p2 == string::npos) + return; +// requesting stations callsign + UrCall = upcase(rcvPayload.substr(p1, p2 - p1)); + p1 = rcvPayload.find(' ', p2+1); + if (p1 == string::npos) { + UrCall.erase(); + return; + } + + p1++; + p2 = rcvPayload.find(" ", p1); + string testcall = upcase(rcvPayload.substr(p1, p2 - p1)); + if (testcall != MyCall) { + UrCall.erase(); + return; + } + + p1++; // *p1 ==> StreamID for requesting station + UrStreamID = rcvPayload[p1]; + p1++; // *p1 ==> requested block size + UrBlockLengthChar = rcvPayload[p1]; + + RxTextQueue.clear();//erase(); + + LinkState = CONNECTED; + timeout = Timeout / ARQLOOPTIME; + + statFrame(); + immediate = true; + primary = true; + printSTATUS(RXCONACK, 5.0); +} + +void arq::parseDISREQ() +{ + if (LinkState == DOWN) return; + TxTextQueue.clear();//erase(); + TxMissing.clear(); + TxBlocks.clear(); + TxPlainTextQueue.clear(); + disackFrame(); + immediate = true; + LinkState = DOWN; + if (rxUrCall) rxUrCall(""); + if (disconnectfnc) disconnectfnc(); + printSTATUS(RXDISCONN, 5.0); +} + +void arq::parseDISACK() +{ + if (rxUrCall) rxUrCall(""); + LinkState = DOWN; + printSTATUS(RXDISCONACK, 5.0); +} + +void arq::parseABORT() +{ + reset(); + if (abortfnc) abortfnc(); + ackAbortFrame(); + immediate = true; + LinkState = CONNECTED; +} + +void arq::parseACKABORT() +{ + reset(); + if (abortfnc) abortfnc(); + LinkState = CONNECTED; +} + +void arq::parseUNPROTO() +{ + size_t p1 = 0, p2 = rcvPayload.find(':'); + if (p2 == string::npos) + return; +// requesting stations callsign + UrCall = upcase(rcvPayload.substr(p1, p2 - p1)); + if (rxUrCall) rxUrCall(UrCall); + if (printRX) printRX(rcvPayload + "\n"); +} + +void arq::parseTALK() +{ + size_t p1 = rcvPayload.find(":73"); + if (p1 == string::npos) + return; + string talktext = rcvPayload.substr(p1 + 4); + if (printTALK) printTALK(talktext); +} + +void arq::parseSTATUS() +{ +// create the missing list +// all reported missing blocks + if (LinkState >= CONNECTED) { + UrLastHeader = rcvPayload[0] - 0x20; // Other station's Header last sent + UrGoodHeader = rcvPayload[1] - 0x20; // Other station's Good Header + UrEndHeader = rcvPayload[2] - 0x20; // Other station's last received Header + + size_t nummissing = rcvPayload.length() - 3; + vector missing; +// append those reported missing + if (nummissing > 0) + for (size_t i = 0; i < nummissing; i++) + missing.push_back(rcvPayload[i+3] - 0x20); +// append those not reported missing from UrEndHeader to LastHeader + if (UrEndHeader != LastHeader) { + int m = UrEndHeader + 1; + if (m > MAXCOUNT) m -= MAXCOUNT; + while (m != LastHeader) { + missing.push_back(m); + m++; + if (m > MAXCOUNT) m -= MAXCOUNT; + } + missing.push_back(LastHeader); + } + + if (missing.empty()) + TxMissing.clear(); + + if (TxMissing.empty() == false) { + list keep; + list::iterator p = TxMissing.begin(); + while (p != TxMissing.end()) { + for (size_t n = 0; n < missing.size(); n++) { + if (p->nbr() == missing[n]) { + keep.push_back(*p); + break; + } + } + p++; + } + TxMissing = keep; + } + } + +// print any txpending blocks up to and including UrGoodHeader + list ::iterator p1 = TxPending.begin(); + + p1 = TxPending.begin(); + while (p1 != TxPending.end()) { + if(p1->nbr() == UrGoodHeader) { + if (printTX) printTX(p1->text()); + TxPending.erase(p1); + break; + } else + if (printTX) printTX(p1->text()); + TxPending.erase(p1); + p1 = TxPending.begin(); + } + + switch (LinkState) { + case WAITFORACK : + LinkState = CONNECTED; + break; + case DISCONNECTING : + if (rxUrCall) rxUrCall(""); + LinkState = DOWN; + break; + case WAITING : + LinkState = CONNECTED; + break; +// case ABORTING : +// reset(); +// if (abortfnc) abortfnc(); +// LinkState = CONNECTED; +// break; +// case ABORT : +// break; + default: break; + } + + printSTATUS(RXSTATUS, 5.0); +} + +void arq::parsePOLL() +{ + if (LinkState == DISCONNECTING || LinkState == DOWN || + LinkState == TIMEDOUT || LinkState == ABORT ) + return; + + statFrame(); + immediate = true; + LinkState = CONNECTED; + printSTATUS(RXPOLL, 5.0); +} + +void arq::parseDATA() +{ + vector::iterator p1, p2; + int n1, n2; + + if (LinkState < CONNECTED) return; // do not respond if DOWN or TIMEDOUT + + for (p1 = RxPending.begin(); p1 < RxPending.end(); p1++) + if (blknbr == p1->nbr()) { + return; + } + + char szStatus[80]; + snprintf(szStatus, sizeof(szStatus),"RX: data block %d", blknbr); + printSTATUS(szStatus, 5.0); + + cTxtBlk tempblk(blknbr, rcvPayload); + RxPending.push_back (tempblk); + + for (p1 = RxPending.begin(); p1 < RxPending.end() - 1; p1++) { + n1 = p1->nbr(); + if (n1 < GoodHeader) n1 += MAXCOUNT; + for (p2 = p1 + 1; p2 < RxPending.end(); p2++) { + n2 = p2->nbr(); + if (n2 < GoodHeader) n2 += MAXCOUNT; + if (n2 < n1) { + tempblk = *p1; + *p1 = *p2; + *p2 = tempblk; + } + } + } +// compute new EndHeader + EndHeader = GoodHeader; + if (!RxPending.empty()) { + p1 = RxPending.end() - 1; + EndHeader = p1->nbr(); + } + +// add RxPending blocks that are consecutive to GoodHeader + p1 = RxPending.begin(); + while (!RxPending.empty()) { + if ((p1->nbr() != (GoodHeader +1) % MAXCOUNT)) + break; + RxTextQueue.append(p1->text()); + GoodHeader = p1->nbr(); + if (printRX) printRX(p1->text()); + RxPending.erase(p1); + p1 = RxPending.begin(); + } + + MissingRxBlocks = ""; + + if (RxPending.empty()) + return; + + int start = (GoodHeader + 1)%MAXCOUNT; + int end = (EndHeader + 1)%MAXCOUNT; + int test; + bool ok; + if (end < start) end += MAXCOUNT; + for (int i = start; i < end; i++) { + test = (i % MAXCOUNT); + ok = false; + for (p1 = RxPending.begin(); p1 < RxPending.end(); p1++) { + if (test == p1->nbr()) { + ok = true; + break; + } + } + if (!ok) + MissingRxBlocks += test + 0x20; + } +} + +bool arq::isUrcall() +{ + if (UrCall.empty()) + return false; + if (rcvPayload.find(UrCall) != string::npos) + return true; + return false; +} + + +// expects to receive a full frame +// txt[0] == SOH +// txt[len - 3] ... txt[len] == CRC +// returns +// -1 invalid frame +// -n failed CRC for text type n +// n valid frame +// rcvPayload will contain the valid payload +// +int arq::parseFrame(string txt) +{ + if ( txt.length() < 8 ) { + return -1; // not a valid frame + } + Ccrc16 testcrc; + size_t len = txt.length(); + + rcvPayload = txt.substr(4, len - 8); + fID = txt[3]; + +// treat unproto TALK as a special case +// no effort made to confirm the data by the CRC value + if (fID == _TALK) { + if (LinkState >= CONNECTED) { + timeout = Timeout / ARQLOOPTIME; + parseTALK(); + retries = Retries; + } + return -1; + } + + string sRcvdCRC = testcrc.scrc16( txt.substr(0, len - 4)); + + if (sRcvdCRC != txt.substr(len - 4) ) { + if (printRX_DEBUG) + printRX_DEBUG("CRC failed\n"); + return -1; // failed CRC test + } + + retries = Retries; + + switch (fID) { + case IDENT : + if (!isUrcall()) + break; + blknbr = fID - 0x20; + parseIDENT(); + if (printRX_DEBUG) { + printRX_DEBUG("IDENT:"); + } + break; + case CONREQ : + if (LinkState > TIMEDOUT) + break; // disallow multiple connects + blknbr = fID - 0x20; + parseCONREQ(); + if (printRX_DEBUG) { + printRX_DEBUG("CONREQ:"); + } + break; + case CONACK : + if (!isUrcall()) + break; + blknbr = fID - 0x20; + parseCONACK(); + if (printRX_DEBUG) { + printRX_DEBUG("CONACK:"); + } + break; + case DISREQ : + if (!isUrcall()) + break; + blknbr = fID - 0x20; + parseDISREQ(); + if (printRX_DEBUG) { + printRX_DEBUG("DISREQ:"); + } + break; + case _DISACK : + if (!isUrcall()) + break; + blknbr = fID - 0x20; + parseDISACK(); + if (printRX_DEBUG) { + printRX_DEBUG("DISACK: "); + } + break; + case STATUS : + if (LinkState == DOWN || LinkState == TIMEOUT) + break; + blknbr = fID - 0x20; + parseSTATUS(); + if (printRX_DEBUG) { + printRX_DEBUG("STATUS:"); + } + break; + case POLL : + if (!isUrcall()) { + break; + } + blknbr = fID - 0x20; + parsePOLL(); + if (printRX_DEBUG) { + printRX_DEBUG("POLL:"); + } + break; + case _ABORT : + if (!isUrcall()) + break; + blknbr = fID - 0x20; + parseABORT(); + if (printRX_DEBUG) { + printRX_DEBUG("RCVD ABORT:"); + } + break; + case _ACKABORT : + blknbr = fID - 0x20; + parseACKABORT(); + if (printRX_DEBUG) { + printRX_DEBUG("RCVD ACK_ABORT:"); + } + break; + case _UNPROTO : + if (LinkState >TIMEDOUT && !isUrcall()) + break; // disallow interruption + blknbr = fID - 0x20; + parseUNPROTO(); + if (printRX_DEBUG) { + printRX_DEBUG("UNPROTO:"); + } + break; + default : + blknbr = fID - 0x20; + parseDATA(); + if (printRX_DEBUG) { + printRX_DEBUG("DATA:"); + } + } + if (printRX_DEBUG) { + printRX_DEBUG(txt); printRX_DEBUG("\n"); + } + + + if (LinkState == CONNECTED) + timeout = Timeout / ARQLOOPTIME; + + return fID; +} + + +void arq::rcvChar( char c ) +{ + if ( c == 0x06 ) { + Sending = 0; + retrytime = rtry(); + timeout = Timeout / ARQLOOPTIME; + tx2txdelay = TxDelay / ARQLOOPTIME; + return; + } + + if (lastRxChar == SOH && c == SOH) // consecutive characters + return; + + if (lastRxChar == EOT && c == EOT) // consecutive characters + return; + + if (RxFrameQueue.empty()) { + if (c == SOH) + RxFrameQueue += c; + } else { + if (c == SOH || c == EOT) { + parseFrame(RxFrameQueue); + RxFrameQueue.clear();//erase(); + if (c == SOH) RxFrameQueue += c; + } else + RxFrameQueue += c; + } + + lastRxChar = c; +} + +//===================================================================== + +void arq::sendText (string txt) +{ + size_t offset = 0; + cTxtBlk tempblk; + if (LinkState < CONNECTED) return; + + Blocks2Send = 0; + while (offset < txt.length()) { + newblocknumber(); + tempblk.nbr(Lastqueued); + tempblk.text(txt.substr(offset, Bufferlength)); + offset += Bufferlength; + TxBlocks.push_back(tempblk); + Blocks2Send++; + } +} + +void arq::sendblocks() +{ + char szStatus[80]; + int missedblks = 0, newblks = 0; + int framecount = 0; + cTxtBlk tempblk; + + if (TxMissing.empty() == false) { + list::iterator p = TxMissing.begin(); + while (p != TxMissing.end()) { + textFrame(*p); + p++; + framecount++; + } + } + missedblks = framecount; + if (!TxBlocks.empty()) { + while (TxBlocks.empty() == false && framecount < maxheaders) { + tempblk = TxBlocks.front(); + if ((tempblk.nbr() + 2)%MAXCOUNT == UrGoodHeader) + break; + TxBlocks.pop_front(); + TxMissing.push_back(tempblk); + TxPending.push_back(tempblk); + textFrame(tempblk); + LastHeader = tempblk.nbr(); + framecount++; + } + } + newblks = framecount - missedblks; + snprintf(szStatus, sizeof(szStatus),"TX: repeat %d new %d", + missedblks, newblks); + printSTATUS(szStatus, 0.0); + + if (!TxMissing.empty() || !TxBlocks.empty()) + pollFrame(); + + if (LinkState != ABORT && LinkState != ABORTING) + LinkState = WAITING; +} + +void arq::connect(string callsign) +{ + UrCall = callsign; + for (size_t i = 0; i < UrCall.length(); i++) + UrCall[i] = toupper(UrCall[i]); + + if (rxUrCall) rxUrCall(UrCall); + TxTextQueue.clear(); + connectFrame(); + LinkState = CONNECTING; + immediate = true; +} + +void arq::disconnect() +{ + Retries = baseRetries; + Timeout = baseTimeout; + RetryTime = baseRetryTime; + totalTx = 0; + nbrbadTx = 0; + + LinkState = DISCONNECT; +} + +void arq::abort() +{ +// bABORT = true; + LinkState = ABORT; +} + + +void arq::sendBeacon (string txt) +{ + string deText = "<<< FLARQ Beacon >>> de "; + deText += MyCall; + TxTextQueue.clear();//erase(); + addToTxQue(deText); + beaconFrame(txt); + immediate = true; + LinkState = DOWN; +} + +void arq::sendPlainText( string txt ) +{ + size_t p = 0; + while (p < txt.length()) { + talkFrame(txt.substr(p, Bufferlength)); + p += Bufferlength; + } +} + +void arq::transmitdata() +{ + if (TxTextQueue.empty() == false) { + sendfnc(TxTextQueue); + Sending = 0x80; + if (printTX_DEBUG) + printTX_DEBUG(TxTextQueue); + TxTextQueue.clear(); + tx2txdelay = TxDelay / ARQLOOPTIME; + return; + } + if (TxPlainTextQueue.empty() == false) { + sendfnc(TxPlainTextQueue); + Sending = 0x80; + if (printTX_DEBUG) + printTX_DEBUG(TxPlainTextQueue); + TxPlainTextQueue.clear(); + tx2txdelay = TxDelay / ARQLOOPTIME; + } +} + +int arq::rtry() +{ + return RetryTime / ARQLOOPTIME; +// return (RetryTime + rand() * 5000 / RAND_MAX) / ARQLOOPTIME; +} + +//--------------------------------------------------------------------- + +void arqloop(void *who) +{ + arq *me = (arq *)who; + char c; + +// check for received chars including 0x06 for Sending = 0 + if (me->getc1(c) == true) { + me->rcvChar(c); + while (me->getc1(c) == true) + me->rcvChar(c); + if (me->tx2txdelay < me->TxDelay / ARQLOOPTIME) + me->tx2txdelay = me->TxDelay / ARQLOOPTIME; + } + if (me->Sending == 0) { // not transmitting +// wait period between transmits + if (me->tx2txdelay > 0) { + me->tx2txdelay--; + } else { + if (me->immediate == true) { + me->transmitdata(); + me->retrytime = me->rtry(); + me->retries = me->Retries; + me->immediate = false; + } else { + switch (me->LinkState) { + case CONNECTING : + break; + case DISCONNECT : + me->LinkState = DISCONNECTING; + me->TxTextQueue.clear(); + me->TxMissing.clear(); + me->TxBlocks.clear(); + me->TxPlainTextQueue.clear(); + me->disconnectFrame(); + me->immediate = true; + break; + case DISCONNECTING : + if (me->retrytime-- == 0) { + me->retrytime = me->rtry(); + if (--me->retries) { + me->TxTextQueue.clear(); + me->TxMissing.clear(); + me->TxBlocks.clear(); + me->TxPlainTextQueue.clear(); + me->disconnectFrame(); + me->transmitdata(); + me->timeout = me->Timeout / ARQLOOPTIME; + } + } + break; + case ABORT : + me->LinkState = ABORTING; + me->TxTextQueue.clear(); + me->TxMissing.clear(); + me->TxBlocks.clear(); + me->TxPlainTextQueue.clear(); + me->tx2txdelay = 5000/ ARQLOOPTIME; // 5 sec delay for abort + me->abortFrame(); + me->immediate = true; + break; + case ABORTING : + if (--me->retrytime == 0) { + me->retrytime = me->rtry(); + if (me->retries--) { + me->TxTextQueue.clear(); + me->TxMissing.clear(); + me->TxBlocks.clear(); + me->TxPlainTextQueue.clear(); + me->abortFrame(); + me->transmitdata(); + me->timeout = me->Timeout / ARQLOOPTIME; + } + } + break; + case WAITING : + if (me->retrytime-- == 0) { + me->retrytime = me->rtry(); + if (--me->retries) { + me->TxTextQueue.clear(); + me->pollFrame(); + me->transmitdata(); + me->nbrbadTx++; + me->timeout = me->Timeout / ARQLOOPTIME; + } + } + break; + case WAITFORACK : + if (me->retrytime-- == 0) { + me->retrytime = me->rtry(); + if (--me->retries) { + me->TxTextQueue.clear(); + me->ackFrame(); + me->transmitdata(); + me->nbrbadTx++; + me->timeout = me->Timeout / ARQLOOPTIME; + } + } + break; + + case CONNECTED : + default: + if (me->TxTextQueue.empty() == false) { + me->transmitdata(); + } else if ( (me->TxMissing.empty() == false) || (me->TxBlocks.empty() == false)) { + me->nbrbadTx += me->TxMissing.size(); + me->sendblocks(); + me->transmitdata(); + } else if ( me->TxPlainTextQueue.empty() == false ) { + me->transmitdata(); + } + break; + } + me->timeout--; + if (me->timeout == 0 // 10000 / ARQLOOPTIME // 10 seconds remaining + && me->LinkState == CONNECTED // link is connected + && me->primary == true ) { // this is the connecting station + if (--me->retries) { // repeat Retries and then allow timeout + me->TxTextQueue.clear(); + me->identFrame(); // send an identity frame to try to keep + me->transmitdata(); // the link up + me->timeout = me->rtry(); //10000 / ARQLOOPTIME + 1; + } + } + if (me->timeout == 0) { + if (me->LinkState == CONNECTED) + me->LinkState = TIMEDOUT; + else + me->LinkState = DOWN; + me->Retries = me->baseRetries; + me->Timeout = me->baseTimeout; + me->RetryTime = me->baseRetryTime; + + me->retries = me->Retries; + me->retrytime = me->rtry(); + me->TxMissing.clear(); + me->TxBlocks.clear(); + me->TxTextQueue.clear(); + me->TxPlainTextQueue.clear(); + me->timeout = me->Timeout / ARQLOOPTIME; + if (me->rxUrCall) me->rxUrCall(""); + } + if (me->retries == 0) { + me->LinkState = DOWN; + me->Retries = me->baseRetries; + me->Timeout = me->baseTimeout; + me->RetryTime = me->baseRetryTime; + + me->retries = me->Retries; + me->retrytime = me->rtry(); + me->TxMissing.clear(); + me->TxBlocks.clear(); + me->TxTextQueue.clear(); + me->TxPlainTextQueue.clear(); + me->timeout = me->Timeout / ARQLOOPTIME; + if (me->rxUrCall) me->rxUrCall(""); + me->printSTATUS(STIMEDOUT, 10.0); + } + } + } + } + + if (me->arqstop) + return; + + Fl::repeat_timeout( ARQLOOPTIME/1000.0, arqloop, me); +} + + +void arq::start_arq() +{ + Fl::add_timeout(1.0, arqloop, this); +} + +//--------------------------------------------------------------------- diff --git a/src/flarq-src/arqdialogs.cxx b/src/flarq-src/arqdialogs.cxx new file mode 100644 index 00000000..cd7ddb3f --- /dev/null +++ b/src/flarq-src/arqdialogs.cxx @@ -0,0 +1,732 @@ +// generated by Fast Light User Interface Designer (fluid) version 1.0109 + +#include "arqdialogs.h" +#include +#include +#include "flarq.h" + +static void cb_flarq(Fl_Double_Window*, void*) { + arqCLOSE(); +} + +Fl_Menu_Bar *mnu=(Fl_Menu_Bar *)0; + +static void cb_mnuExit(Fl_Menu_*, void*) { + arqCLOSE(); +} + +static void cb_mnuSendEmail(Fl_Menu_*, void*) { + sendEmailFile(); +} + +static void cb_mnuSendText(Fl_Menu_*, void*) { + sendAsciiFile(); +} + +static void cb_mnuSendImage(Fl_Menu_*, void*) { + sendImageFile(); +} + +static void cb_mnuSendBinary(Fl_Menu_*, void*) { + sendBinaryFile(); +} + +static void cb_mnuCompose(Fl_Menu_*, void*) { + ComposeMail(); +} + +static void cb_mnuConfig(Fl_Menu_*, void*) { + cbMenuConfig(); +} + +static void cb_mnuHowTo(Fl_Menu_*, void*) { + help_cb(); +} + +static void cb_mnuAbout(Fl_Menu_*, void*) { + cbMenuAbout(); +} + +Fl_Menu_Item menu_mnu[] = { + {"&File", 0, 0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0}, + {"E&xit", 0, (Fl_Callback*)cb_mnuExit, 0, 0, FL_NORMAL_LABEL, 0, 14, 0}, + {0,0,0,0,0,0,0,0,0}, + {"&Send", 0, 0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0}, + {"Email", 0, (Fl_Callback*)cb_mnuSendEmail, 0, 0, FL_NORMAL_LABEL, 0, 14, 0}, + {"Text File", 0, (Fl_Callback*)cb_mnuSendText, 0, 0, FL_NORMAL_LABEL, 0, 14, 0}, + {"Image File", 0, (Fl_Callback*)cb_mnuSendImage, 0, 0, FL_NORMAL_LABEL, 0, 14, 0}, + {"Binary File", 0, (Fl_Callback*)cb_mnuSendBinary, 0, 0, FL_NORMAL_LABEL, 0, 14, 0}, + {0,0,0,0,0,0,0,0,0}, + {"Compose", 0, (Fl_Callback*)cb_mnuCompose, 0, 0, FL_NORMAL_LABEL, 0, 14, 0}, + {"&Config", 0, (Fl_Callback*)cb_mnuConfig, 0, 0, FL_NORMAL_LABEL, 0, 14, 0}, + {"Help", 0, 0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0}, + {"How To", 0, (Fl_Callback*)cb_mnuHowTo, 0, 0, FL_NORMAL_LABEL, 0, 14, 0}, + {"About", 0, (Fl_Callback*)cb_mnuAbout, 0, 0, FL_NORMAL_LABEL, 0, 14, 0}, + {0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0} +}; + +Fl_Button *btnCONNECT=(Fl_Button *)0; + +static void cb_btnCONNECT(Fl_Button*, void*) { + arqCONNECT(); +} + +Fl_Input2 *txtURCALL=(Fl_Input2 *)0; + +Fl_Light_Button *btnBEACON=(Fl_Light_Button *)0; + +static void cb_btnBEACON(Fl_Light_Button*, void*) { + arqBEACON(); +} + +Fl_Input2 *txtBeaconing=(Fl_Input2 *)0; + +Fl_Box *indCONNECT=(Fl_Box *)0; + +Fl_Input2 *txtState=(Fl_Input2 *)0; + +Fl_Text_Display *txtARQ=(Fl_Text_Display *)0; + +Fl_Input2 *txtStatus=(Fl_Input2 *)0; + +Fl_Input2 *txtStatus2=(Fl_Input2 *)0; + +Fl_Progress *prgStatus=(Fl_Progress *)0; + +Fl_Button *btnClearText=(Fl_Button *)0; + +static void cb_btnClearText(Fl_Button*, void*) { + cbClearText(); +} + +Fl_Text_Display *txtRX=(Fl_Text_Display *)0; + +Fl_Input2 *txtTX=(Fl_Input2 *)0; + +static void cb_txtTX(Fl_Input2*, void*) { + cbSendTalk(); +} + +Fl_Button *btnSendTalk=(Fl_Button *)0; + +static void cb_btnSendTalk(Fl_Button*, void*) { + cbClearTalk(); +} + +Fl_Double_Window* arq_dialog() { + Fl_Double_Window* w; + { Fl_Double_Window* o = new Fl_Double_Window(515, 415, "flarq"); + w = o; + o->color(FL_LIGHT1); + o->callback((Fl_Callback*)cb_flarq); + { mnu = new Fl_Menu_Bar(0, 0, 516, 22); + mnu->menu(menu_mnu); + } // Fl_Menu_Bar* mnu + { Fl_Group* o = new Fl_Group(0, 25, 515, 60); + { Fl_Group* o = new Fl_Group(0, 25, 515, 31); + o->box(FL_ENGRAVED_FRAME); + { btnCONNECT = new Fl_Button(5, 28, 90, 24, "Connnect"); + btnCONNECT->tooltip("Connect to other station"); + btnCONNECT->color(FL_LIGHT1); + btnCONNECT->callback((Fl_Callback*)cb_btnCONNECT); + } // Fl_Button* btnCONNECT + { txtURCALL = new Fl_Input2(97, 28, 70, 24); + txtURCALL->tooltip("Connect-to callsign"); + txtURCALL->box(FL_DOWN_BOX); + txtURCALL->color(FL_BACKGROUND2_COLOR); + txtURCALL->selection_color(FL_SELECTION_COLOR); + txtURCALL->labeltype(FL_NORMAL_LABEL); + txtURCALL->labelfont(0); + txtURCALL->labelsize(14); + txtURCALL->labelcolor(FL_FOREGROUND_COLOR); + txtURCALL->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE); + txtURCALL->when(FL_WHEN_RELEASE); + } // Fl_Input2* txtURCALL + { btnBEACON = new Fl_Light_Button(168, 28, 79, 24, "Beacon"); + btnBEACON->tooltip("Beacon ON / OFF"); + btnBEACON->selection_color((Fl_Color)2); + btnBEACON->callback((Fl_Callback*)cb_btnBEACON); + } // Fl_Light_Button* btnBEACON + { Fl_Input2* o = txtBeaconing = new Fl_Input2(249, 28, 261, 24, "output:"); + txtBeaconing->box(FL_FLAT_BOX); + txtBeaconing->color(FL_LIGHT1); + txtBeaconing->selection_color(FL_SELECTION_COLOR); + txtBeaconing->labeltype(FL_NORMAL_LABEL); + txtBeaconing->labelfont(0); + txtBeaconing->labelsize(14); + txtBeaconing->labelcolor(FL_FOREGROUND_COLOR); + txtBeaconing->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE); + txtBeaconing->when(FL_WHEN_RELEASE); + Fl_Group::current()->resizable(txtBeaconing); + o->type(FL_NORMAL_OUTPUT); + } // Fl_Input2* txtBeaconing + o->end(); + } // Fl_Group* o + { Fl_Group* o = new Fl_Group(0, 54, 515, 31); + o->box(FL_ENGRAVED_FRAME); + { indCONNECT = new Fl_Box(5, 60, 18, 18); + indCONNECT->tooltip("ARQ state"); + indCONNECT->box(FL_DIAMOND_DOWN_BOX); + indCONNECT->color(FL_LIGHT1); + indCONNECT->labelfont(13); + indCONNECT->align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE); + } // Fl_Box* indCONNECT + { Fl_Input2* o = txtState = new Fl_Input2(27, 57, 483, 24, "Disconnecting"); + txtState->box(FL_FLAT_BOX); + txtState->color(FL_LIGHT1); + txtState->selection_color(FL_SELECTION_COLOR); + txtState->labeltype(FL_NORMAL_LABEL); + txtState->labelfont(0); + txtState->labelsize(14); + txtState->labelcolor(FL_FOREGROUND_COLOR); + txtState->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE); + txtState->when(FL_WHEN_RELEASE); + Fl_Group::current()->resizable(txtState); + o->type(FL_NORMAL_OUTPUT); + } // Fl_Input2* txtState + o->end(); + } // Fl_Group* o + o->end(); + } // Fl_Group* o + { txtARQ = new Fl_Text_Display(0, 87, 515, 117); + txtARQ->box(FL_DOWN_BOX); + txtARQ->textfont(4); + Fl_Group::current()->resizable(txtARQ); + } // Fl_Text_Display* txtARQ + { Fl_Group* o = new Fl_Group(0, 206, 516, 26); + o->box(FL_DOWN_BOX); + { Fl_Input2* o = txtStatus = new Fl_Input2(5, 208, 220, 22); + txtStatus->tooltip("Status messages"); + txtStatus->box(FL_DOWN_BOX); + txtStatus->color(FL_BACKGROUND2_COLOR); + txtStatus->selection_color(FL_SELECTION_COLOR); + txtStatus->labeltype(FL_NORMAL_LABEL); + txtStatus->labelfont(0); + txtStatus->labelsize(14); + txtStatus->labelcolor(FL_FOREGROUND_COLOR); + txtStatus->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE); + txtStatus->when(FL_WHEN_RELEASE); + Fl_Group::current()->resizable(txtStatus); + o->type(FL_NORMAL_OUTPUT); + } // Fl_Input2* txtStatus + { Fl_Input2* o = txtStatus2 = new Fl_Input2(225, 208, 170, 22); + txtStatus2->box(FL_DOWN_BOX); + txtStatus2->color(FL_BACKGROUND2_COLOR); + txtStatus2->selection_color(FL_SELECTION_COLOR); + txtStatus2->labeltype(FL_NORMAL_LABEL); + txtStatus2->labelfont(0); + txtStatus2->labelsize(14); + txtStatus2->labelcolor(FL_FOREGROUND_COLOR); + txtStatus2->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE); + txtStatus2->when(FL_WHEN_RELEASE); + o->type(FL_NORMAL_OUTPUT); + } // Fl_Input2* txtStatus2 + { Fl_Progress* o = prgStatus = new Fl_Progress(395, 210, 70, 18); + prgStatus->tooltip("Tx/Rx ARQ file transfer progress"); + prgStatus->selection_color((Fl_Color)70); + prgStatus->labelfont(1); + o->minimum(0.0); + o->maximum(1.0); + } // Fl_Progress* prgStatus + { btnClearText = new Fl_Button(468, 210, 45, 20, "Clear"); + btnClearText->callback((Fl_Callback*)cb_btnClearText); + } // Fl_Button* btnClearText + o->end(); + } // Fl_Group* o + { Fl_Group* o = new Fl_Group(0, 235, 515, 180, "Plain Talk"); + o->box(FL_ENGRAVED_FRAME); + o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE); + { txtRX = new Fl_Text_Display(5, 255, 505, 130); + txtRX->box(FL_DOWN_BOX); + txtRX->textfont(4); + Fl_Group::current()->resizable(txtRX); + } // Fl_Text_Display* txtRX + { Fl_Group* o = new Fl_Group(0, 387, 515, 28); + o->box(FL_ENGRAVED_FRAME); + { txtTX = new Fl_Input2(5, 390, 450, 22, "input:"); + txtTX->tooltip("Plain talk text - ENTER to send"); + txtTX->box(FL_DOWN_BOX); + txtTX->color(FL_BACKGROUND2_COLOR); + txtTX->selection_color(FL_SELECTION_COLOR); + txtTX->labeltype(FL_NORMAL_LABEL); + txtTX->labelfont(0); + txtTX->labelsize(14); + txtTX->labelcolor(FL_FOREGROUND_COLOR); + txtTX->callback((Fl_Callback*)cb_txtTX); + txtTX->align(FL_ALIGN_CENTER); + txtTX->when(FL_WHEN_ENTER_KEY); + Fl_Group::current()->resizable(txtTX); + txtTX->value(""); + txtTX->maximum_size(80); + } // Fl_Input2* txtTX + { btnSendTalk = new Fl_Button(460, 390, 49, 22, "Clear"); + btnSendTalk->callback((Fl_Callback*)cb_btnSendTalk); + } // Fl_Button* btnSendTalk + o->end(); + } // Fl_Group* o + o->end(); + } // Fl_Group* o + o->end(); + } // Fl_Double_Window* o + return w; +} + +Fl_Input2 *txtMyCall=(Fl_Input2 *)0; + +static void cb_txtMyCall(Fl_Input2* o, void*) { + changeMyCall(o->value()); +} + +Fl_Input2 *txtFolder=(Fl_Input2 *)0; + +static void cb_txtFolder(Fl_Input2* o, void*) { + InFolder = o->value(); +} + +Fl_Input2 *txtOutputFolder=(Fl_Input2 *)0; + +static void cb_txtOutputFolder(Fl_Input2* o, void*) { + OutFolder = o->value(); +} + +Fl_Input2 *txtMail_IN=(Fl_Input2 *)0; + +static void cb_txtMail_IN(Fl_Input2* o, void*) { + MailInFolder = o->value(); +} + +Fl_Input2 *txtMail_OUT=(Fl_Input2 *)0; + +static void cb_txtMail_OUT(Fl_Input2* o, void*) { + MailOutFolder = o->value(); +} + +Fl_Input2 *txtMail_SENT=(Fl_Input2 *)0; + +static void cb_txtMail_SENT(Fl_Input2* o, void*) { + MailSentFolder = o->value(); +} + +Fl_Check_Button *btnSylpheedMail=(Fl_Check_Button *)0; + +static void cb_btnSylpheedMail(Fl_Check_Button* o, void*) { + bSylpheedFolder = o->value(); +} + +Fl_Spinner *spnExponent=(Fl_Spinner *)0; + +static void cb_spnExponent(Fl_Spinner* o, void*) { + exponent = (int)o->value(); +switch (exponent) { +case 4: txtBlockSize->value("16"); break; +case 5: txtBlockSize->value("32"); break; +case 6: txtBlockSize->value("64"); break; +case 7: txtBlockSize->value("128"); break; +case 8: txtBlockSize->value("256"); break; +default: +txtBlockSize->value("32");break; +} +cbSetConfig(); +} + +Fl_Spinner *spnRetries=(Fl_Spinner *)0; + +static void cb_spnRetries(Fl_Spinner* o, void*) { + iretries = (int)o->value(); +cbSetConfig(); +} + +Fl_Spinner *spnWaitTime=(Fl_Spinner *)0; + +static void cb_spnWaitTime(Fl_Spinner* o, void*) { + iwaittime = (int)(1000 * o->value()); +cbSetConfig(); +} + +Fl_Spinner *spnTimeout=(Fl_Spinner *)0; + +static void cb_spnTimeout(Fl_Spinner* o, void*) { + itimeout = (int)(o->value() * 1000.0); +cbSetConfig(); +} + +Fl_Spinner *spnTxDelay=(Fl_Spinner *)0; + +static void cb_spnTxDelay(Fl_Spinner* o, void*) { + txdelay = (int)o->value(); +cbSetConfig(); +} + +Fl_Spinner *spnBcnInterval=(Fl_Spinner *)0; + +static void cb_spnBcnInterval(Fl_Spinner* o, void*) { + bcnInterval = (int)o->value(); +cbSetConfig(); +} + +Fl_Input2 *txtBlockSize=(Fl_Input2 *)0; + +Fl_Button *btnOK=(Fl_Button *)0; + +static void cb_btnOK(Fl_Button*, void*) { + closeConfig(); +} + +Fl_Input2 *txtBEACONTXT=(Fl_Input2 *)0; + +static void cb_txtBEACONTXT(Fl_Input2* o, void*) { + changeBeaconText(o->value()); +} + +Fl_Double_Window* arq_configure() { + Fl_Double_Window* w; + { Fl_Double_Window* o = new Fl_Double_Window(610, 195, "Configure flarq"); + w = o; + { Fl_Group* o = new Fl_Group(2, 2, 190, 166); + o->box(FL_ENGRAVED_FRAME); + { Fl_Input2* o = txtMyCall = new Fl_Input2(5, 22, 100, 24, "My Call:"); + txtMyCall->box(FL_DOWN_BOX); + txtMyCall->color(FL_BACKGROUND2_COLOR); + txtMyCall->selection_color(FL_SELECTION_COLOR); + txtMyCall->labeltype(FL_NORMAL_LABEL); + txtMyCall->labelfont(0); + txtMyCall->labelsize(14); + txtMyCall->labelcolor(FL_FOREGROUND_COLOR); + txtMyCall->callback((Fl_Callback*)cb_txtMyCall); + txtMyCall->align(FL_ALIGN_TOP_LEFT); + txtMyCall->when(FL_WHEN_RELEASE); + o->value(MyCall.c_str()); + } // Fl_Input2* txtMyCall + { Fl_Group* o = new Fl_Group(2, 60, 190, 105, "Text/Binary Files"); + o->box(FL_ENGRAVED_FRAME); + o->align(FL_ALIGN_TOP|FL_ALIGN_INSIDE); + { Fl_Input2* o = txtFolder = new Fl_Input2(6, 96, 180, 24, "In folder:"); + txtFolder->tooltip("Folder (in $HOME) to store incoming files"); + txtFolder->box(FL_DOWN_BOX); + txtFolder->color(FL_BACKGROUND2_COLOR); + txtFolder->selection_color(FL_SELECTION_COLOR); + txtFolder->labeltype(FL_NORMAL_LABEL); + txtFolder->labelfont(0); + txtFolder->labelsize(14); + txtFolder->labelcolor(FL_FOREGROUND_COLOR); + txtFolder->callback((Fl_Callback*)cb_txtFolder); + txtFolder->align(FL_ALIGN_TOP_LEFT); + txtFolder->when(FL_WHEN_CHANGED); + o->value(InFolder.c_str()); + } // Fl_Input2* txtFolder + { Fl_Input2* o = txtOutputFolder = new Fl_Input2(6, 138, 180, 24, "Out folder:"); + txtOutputFolder->tooltip("Folder (in $HOME) to store outgoing files"); + txtOutputFolder->box(FL_DOWN_BOX); + txtOutputFolder->color(FL_BACKGROUND2_COLOR); + txtOutputFolder->selection_color(FL_SELECTION_COLOR); + txtOutputFolder->labeltype(FL_NORMAL_LABEL); + txtOutputFolder->labelfont(0); + txtOutputFolder->labelsize(14); + txtOutputFolder->labelcolor(FL_FOREGROUND_COLOR); + txtOutputFolder->callback((Fl_Callback*)cb_txtOutputFolder); + txtOutputFolder->align(FL_ALIGN_TOP_LEFT); + txtOutputFolder->when(FL_WHEN_CHANGED); + o->value(OutFolder.c_str()); + } // Fl_Input2* txtOutputFolder + o->end(); + } // Fl_Group* o + o->end(); + } // Fl_Group* o + { Fl_Group* o = new Fl_Group(194, 3, 190, 164, "Mail Client Files"); + o->box(FL_ENGRAVED_FRAME); + o->align(FL_ALIGN_TOP|FL_ALIGN_INSIDE); + { Fl_Input2* o = txtMail_IN = new Fl_Input2(200, 37, 178, 24, "Mail In:"); + txtMail_IN->tooltip("Folder to store incoming files"); + txtMail_IN->box(FL_DOWN_BOX); + txtMail_IN->color(FL_BACKGROUND2_COLOR); + txtMail_IN->selection_color(FL_SELECTION_COLOR); + txtMail_IN->labeltype(FL_NORMAL_LABEL); + txtMail_IN->labelfont(0); + txtMail_IN->labelsize(14); + txtMail_IN->labelcolor(FL_FOREGROUND_COLOR); + txtMail_IN->callback((Fl_Callback*)cb_txtMail_IN); + txtMail_IN->align(FL_ALIGN_TOP_LEFT); + txtMail_IN->when(FL_WHEN_CHANGED); + o->value(MailInFolder.c_str()); + } // Fl_Input2* txtMail_IN + { Fl_Input2* o = txtMail_OUT = new Fl_Input2(200, 78, 178, 24, "Mail Out:"); + txtMail_OUT->tooltip("Folder to store outgoing files"); + txtMail_OUT->box(FL_DOWN_BOX); + txtMail_OUT->color(FL_BACKGROUND2_COLOR); + txtMail_OUT->selection_color(FL_SELECTION_COLOR); + txtMail_OUT->labeltype(FL_NORMAL_LABEL); + txtMail_OUT->labelfont(0); + txtMail_OUT->labelsize(14); + txtMail_OUT->labelcolor(FL_FOREGROUND_COLOR); + txtMail_OUT->callback((Fl_Callback*)cb_txtMail_OUT); + txtMail_OUT->align(FL_ALIGN_TOP_LEFT); + txtMail_OUT->when(FL_WHEN_CHANGED); + o->value(MailOutFolder.c_str()); + } // Fl_Input2* txtMail_OUT + { Fl_Input2* o = txtMail_SENT = new Fl_Input2(200, 119, 178, 24, "Mail Sent:"); + txtMail_SENT->tooltip("Folder to store outgoing files"); + txtMail_SENT->box(FL_DOWN_BOX); + txtMail_SENT->color(FL_BACKGROUND2_COLOR); + txtMail_SENT->selection_color(FL_SELECTION_COLOR); + txtMail_SENT->labeltype(FL_NORMAL_LABEL); + txtMail_SENT->labelfont(0); + txtMail_SENT->labelsize(14); + txtMail_SENT->labelcolor(FL_FOREGROUND_COLOR); + txtMail_SENT->callback((Fl_Callback*)cb_txtMail_SENT); + txtMail_SENT->align(FL_ALIGN_TOP_LEFT); + txtMail_SENT->when(FL_WHEN_CHANGED); + o->value(MailSentFolder.c_str()); + } // Fl_Input2* txtMail_SENT + { Fl_Check_Button* o = btnSylpheedMail = new Fl_Check_Button(200, 146, 175, 15, "Sylpheed Mail Client"); + btnSylpheedMail->tooltip("Check ONLY if Sylpheed is used as mail client"); + btnSylpheedMail->down_box(FL_DOWN_BOX); + btnSylpheedMail->callback((Fl_Callback*)cb_btnSylpheedMail); + o->value(bSylpheedFolder); + } // Fl_Check_Button* btnSylpheedMail + o->end(); + } // Fl_Group* o + { Fl_Group* o = new Fl_Group(386, 3, 224, 163); + o->box(FL_ENGRAVED_FRAME); + { Fl_Spinner* o = spnExponent = new Fl_Spinner(464, 138, 30, 22, "Exponent:"); + spnExponent->tooltip("block size = 2^exponent"); + spnExponent->value(1); + spnExponent->callback((Fl_Callback*)cb_spnExponent); + o->minimum(4); + o->maximum(8); + o->step(1); + o->value(exponent); + } // Fl_Spinner* spnExponent + { Fl_Spinner* o = spnRetries = new Fl_Spinner(558, 7, 45, 22, "Retries:"); + spnRetries->tooltip("# retries before connection declared down"); + spnRetries->value(1); + spnRetries->callback((Fl_Callback*)cb_spnRetries); + o->minimum(2); + o->maximum(20); + o->step(1); + o->value(iretries); + } // Fl_Spinner* spnRetries + { Fl_Spinner* o = spnWaitTime = new Fl_Spinner(533, 33, 70, 22, "Wait time (sec):"); + spnWaitTime->tooltip("time between retries"); + spnWaitTime->value(1); + spnWaitTime->callback((Fl_Callback*)cb_spnWaitTime); + o->minimum(10); + o->maximum(30); + o->step(5); + o->value(iwaittime/1000); + } // Fl_Spinner* spnWaitTime + { Fl_Spinner* o = spnTimeout = new Fl_Spinner(533, 59, 70, 22, "Timeout (sec):"); + spnTimeout->tooltip("Time out for dead connection"); + spnTimeout->value(1); + spnTimeout->callback((Fl_Callback*)cb_spnTimeout); + o->minimum(30); + o->maximum(300); + o->step(15); + o->value(itimeout / 1000); + } // Fl_Spinner* spnTimeout + { Fl_Spinner* o = spnTxDelay = new Fl_Spinner(533, 85, 70, 22, "Tx delay (msec):"); + spnTxDelay->tooltip("delay from Rx to Tx"); + spnTxDelay->value(1); + spnTxDelay->callback((Fl_Callback*)cb_spnTxDelay); + o->minimum(200); + o->maximum(2000); + o->step(100); + o->value(txdelay); + } // Fl_Spinner* spnTxDelay + { Fl_Spinner* o = spnBcnInterval = new Fl_Spinner(554, 111, 49, 22, "Beacon interval (sec)"); + spnBcnInterval->tooltip("Time between beacon transmissions"); + spnBcnInterval->value(1); + spnBcnInterval->callback((Fl_Callback*)cb_spnBcnInterval); + o->minimum(15); o->maximum(600); + o->step(15); + o->value(bcnInterval); + } // Fl_Spinner* spnBcnInterval + { Fl_Input2* o = txtBlockSize = new Fl_Input2(568, 137, 35, 24, " = Blk Size"); + txtBlockSize->box(FL_DOWN_BOX); + txtBlockSize->color(FL_BACKGROUND2_COLOR); + txtBlockSize->selection_color(FL_SELECTION_COLOR); + txtBlockSize->labeltype(FL_NORMAL_LABEL); + txtBlockSize->labelfont(0); + txtBlockSize->labelsize(14); + txtBlockSize->labelcolor(FL_FOREGROUND_COLOR); + txtBlockSize->align(FL_ALIGN_LEFT); + txtBlockSize->when(FL_WHEN_RELEASE); + switch (exponent) { +case 4: o->value("16"); break; +case 5: o->value("32"); break; +case 6: o->value("64"); break; +case 7: o->value("128"); break; +default: +o->value("32");break; +} +o->type(FL_NORMAL_OUTPUT); + } // Fl_Input2* txtBlockSize + o->end(); + } // Fl_Group* o + { btnOK = new Fl_Button(540, 169, 62, 24, "Ok"); + btnOK->callback((Fl_Callback*)cb_btnOK); + } // Fl_Button* btnOK + { Fl_Input2* o = txtBEACONTXT = new Fl_Input2(90, 168, 443, 24, "Beacon Text"); + txtBEACONTXT->tooltip("Text for the beacon 64 chars max"); + txtBEACONTXT->box(FL_DOWN_BOX); + txtBEACONTXT->color(FL_BACKGROUND2_COLOR); + txtBEACONTXT->selection_color(FL_SELECTION_COLOR); + txtBEACONTXT->labeltype(FL_NORMAL_LABEL); + txtBEACONTXT->labelfont(0); + txtBEACONTXT->labelsize(14); + txtBEACONTXT->labelcolor(FL_FOREGROUND_COLOR); + txtBEACONTXT->callback((Fl_Callback*)cb_txtBEACONTXT); + txtBEACONTXT->align(FL_ALIGN_LEFT); + txtBEACONTXT->when(FL_WHEN_RELEASE); + Fl_Group::current()->resizable(txtBEACONTXT); + o->value(beacontext.c_str()); + } // Fl_Input2* txtBEACONTXT + o->end(); + } // Fl_Double_Window* o + return w; +} + +Table *tblOutgoing=(Table *)0; + +Fl_Button *send_Cancel=(Fl_Button *)0; + +static void cb_send_Cancel(Fl_Button*, void*) { + sendCancel(); +} + +Fl_Return_Button *send_OK=(Fl_Return_Button *)0; + +static void cb_send_OK(Fl_Return_Button*, void*) { + sendOK(); +} + +Fl_Double_Window* arq_SendSelect() { + Fl_Double_Window* w; + { Fl_Double_Window* o = new Fl_Double_Window(500, 170, "Select Email"); + w = o; + { tblOutgoing = new Table(0, 3, 500, 140); + tblOutgoing->box(FL_DOWN_BOX); + tblOutgoing->color(FL_BACKGROUND2_COLOR); + tblOutgoing->selection_color((Fl_Color)246); + tblOutgoing->labeltype(FL_NORMAL_LABEL); + tblOutgoing->labelfont(0); + tblOutgoing->labelsize(14); + tblOutgoing->labelcolor(FL_FOREGROUND_COLOR); + tblOutgoing->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); + tblOutgoing->when(FL_WHEN_RELEASE); + } // Table* tblOutgoing + { send_Cancel = new Fl_Button(335, 145, 70, 20, "Cancel"); + send_Cancel->callback((Fl_Callback*)cb_send_Cancel); + } // Fl_Button* send_Cancel + { send_OK = new Fl_Return_Button(420, 145, 72, 20, "OK"); + send_OK->callback((Fl_Callback*)cb_send_OK); + } // Fl_Return_Button* send_OK + o->set_modal(); + o->end(); + o->resizable(o); + } // Fl_Double_Window* o + return w; +} + +Fl_Input2 *inpMailTo=(Fl_Input2 *)0; + +Fl_Input2 *inpMailSubj=(Fl_Input2 *)0; + +Fl_Text_Editor *txtMailText=(Fl_Text_Editor *)0; + +Fl_Button *btnOpenComposedMail=(Fl_Button *)0; + +static void cb_btnOpenComposedMail(Fl_Button*, void*) { + cb_OpenComposeMail(); +} + +Fl_Button *btnClearComposer=(Fl_Button *)0; + +static void cb_btnClearComposer(Fl_Button*, void*) { + cb_ClearComposer(); +} + +Fl_Button *btnUseTemplate=(Fl_Button *)0; + +static void cb_btnUseTemplate(Fl_Button*, void*) { + cb_UseTemplate(); +} + +Fl_Button *btnCancelComposedMail=(Fl_Button *)0; + +static void cb_btnCancelComposedMail(Fl_Button*, void*) { + cb_CancelComposeMail(); +} + +Fl_Button *btnSaveComposedMail=(Fl_Button *)0; + +static void cb_btnSaveComposedMail(Fl_Button*, void*) { + cb_SaveComposeMail(); +} + +Fl_Double_Window* arq_composer() { + Fl_Double_Window* w; + { Fl_Double_Window* o = new Fl_Double_Window(515, 275, "Flarq Mail Composer"); + w = o; + { inpMailTo = new Fl_Input2(48, 4, 460, 24, "To:"); + inpMailTo->box(FL_DOWN_BOX); + inpMailTo->color(FL_BACKGROUND2_COLOR); + inpMailTo->selection_color(FL_SELECTION_COLOR); + inpMailTo->labeltype(FL_NORMAL_LABEL); + inpMailTo->labelfont(0); + inpMailTo->labelsize(14); + inpMailTo->labelcolor(FL_FOREGROUND_COLOR); + inpMailTo->align(FL_ALIGN_LEFT); + inpMailTo->when(FL_WHEN_RELEASE); + } // Fl_Input2* inpMailTo + { inpMailSubj = new Fl_Input2(48, 30, 460, 24, "Subj:"); + inpMailSubj->box(FL_DOWN_BOX); + inpMailSubj->color(FL_BACKGROUND2_COLOR); + inpMailSubj->selection_color(FL_SELECTION_COLOR); + inpMailSubj->labeltype(FL_NORMAL_LABEL); + inpMailSubj->labelfont(0); + inpMailSubj->labelsize(14); + inpMailSubj->labelcolor(FL_FOREGROUND_COLOR); + inpMailSubj->align(FL_ALIGN_LEFT); + inpMailSubj->when(FL_WHEN_RELEASE); + } // Fl_Input2* inpMailSubj + { txtMailText = new Fl_Text_Editor(0, 56, 510, 188); + Fl_Group::current()->resizable(txtMailText); + } // Fl_Text_Editor* txtMailText + { Fl_Pack* o = new Fl_Pack(0, 247, 515, 28); + o->type(1); + { btnOpenComposedMail = new Fl_Button(4, 251, 70, 20, "Open"); + btnOpenComposedMail->tooltip("Open existing Composed email"); + btnOpenComposedMail->callback((Fl_Callback*)cb_btnOpenComposedMail); + } // Fl_Button* btnOpenComposedMail + { new Fl_Box(75, 251, 5, 20); + } // Fl_Box* o + { btnClearComposer = new Fl_Button(81, 251, 70, 20, "Clear"); + btnClearComposer->tooltip("Clear all fields"); + btnClearComposer->callback((Fl_Callback*)cb_btnClearComposer); + } // Fl_Button* btnClearComposer + { new Fl_Box(152, 251, 5, 20); + } // Fl_Box* o + { btnUseTemplate = new Fl_Button(159, 251, 70, 20, "Template"); + btnUseTemplate->tooltip("Use template file"); + btnUseTemplate->callback((Fl_Callback*)cb_btnUseTemplate); + } // Fl_Button* btnUseTemplate + { Fl_Box* o = new Fl_Box(230, 251, 127, 20); + Fl_Group::current()->resizable(o); + } // Fl_Box* o + { btnCancelComposedMail = new Fl_Button(358, 251, 70, 20, "Cancel"); + btnCancelComposedMail->tooltip("Close Dialog"); + btnCancelComposedMail->callback((Fl_Callback*)cb_btnCancelComposedMail); + } // Fl_Button* btnCancelComposedMail + { new Fl_Box(429, 251, 5, 20); + } // Fl_Box* o + { btnSaveComposedMail = new Fl_Button(436, 251, 70, 20, "Save"); + btnSaveComposedMail->tooltip("Save this message (shift click Save Template)"); + btnSaveComposedMail->callback((Fl_Callback*)cb_btnSaveComposedMail); + } // Fl_Button* btnSaveComposedMail + o->end(); + } // Fl_Pack* o + o->end(); + } // Fl_Double_Window* o + return w; +} diff --git a/src/flarq-src/arqdialogs.fl b/src/flarq-src/arqdialogs.fl new file mode 100644 index 00000000..f1ed3422 --- /dev/null +++ b/src/flarq-src/arqdialogs.fl @@ -0,0 +1,445 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0108 +header_name {.h} +code_name {.cxx} +decl {\#include } {} + +decl {\#include } {} + +decl {\#include "flarq.h"} {} + +decl {\#include "flinput2.h"} {public +} + +Function {arq_dialog()} {open +} { + Fl_Window {} { + label flarq + callback {arqCLOSE();} open + xywh {415 60 515 415} type Double color 50 resizable visible + } { + Fl_Menu_Bar mnu {open + xywh {0 0 516 22} + } { + Submenu {} { + label {&File} open + xywh {0 0 70 21} + } { + MenuItem mnuExit { + label {E&xit} + callback {arqCLOSE();} + xywh {0 0 36 21} + } + } + Submenu mnuSend { + label {&Send} open + xywh {0 0 70 21} + } { + MenuItem mnuSendEmail { + label Email + callback {sendEmailFile();} + xywh {0 0 34 21} + } + MenuItem mnuSendText { + label {Text File} + callback {sendAsciiFile();} + xywh {0 0 36 21} + } + MenuItem mnuSendImage { + label {Image File} + callback {sendImageFile();} + xywh {0 0 36 21} + } + MenuItem mnuSendBinary { + label {Binary File} + callback {sendBinaryFile();} + xywh {0 0 36 21} + } + } + MenuItem mnuCompose { + label Compose + callback {ComposeMail();} + xywh {0 0 30 20} + code0 {extern void ComposeMail();} + } + MenuItem mnuConfig { + label {&Config} + callback {cbMenuConfig();} + xywh {0 0 36 21} + code0 {extern void cbMenuConfig();} + } + Submenu mnuHelp { + label Help open + xywh {0 0 62 20} + } { + MenuItem mnuHowTo { + label {How To} + callback {help_cb();} + xywh {0 0 30 20} + } + MenuItem mnuAbout { + label About + callback {cbMenuAbout();} + xywh {5 5 36 21} + code0 {extern void cbMenuAbout();} + } + } + } + Fl_Group {} {open + xywh {0 25 515 60} + } { + Fl_Group {} {open + xywh {0 25 515 31} box ENGRAVED_FRAME + } { + Fl_Button btnCONNECT { + label Connnect + callback {arqCONNECT();} + tooltip {Connect to other station} xywh {5 28 90 24} color 50 + } + Fl_Input txtURCALL { + tooltip {Connect-to callsign} xywh {97 28 70 24} align 20 + class Fl_Input2 + } + Fl_Light_Button btnBEACON { + label Beacon + callback {arqBEACON();} + tooltip {Beacon ON / OFF} xywh {168 28 79 24} selection_color 2 + } + Fl_Output txtBeaconing { + label {output:} + xywh {249 28 261 24} box FLAT_BOX color 50 align 20 resizable + code0 {o->type(FL_NORMAL_OUTPUT);} + class Fl_Input2 + } + } + Fl_Group {} {open + xywh {0 54 515 31} box ENGRAVED_FRAME + } { + Fl_Box indCONNECT { + tooltip {ARQ state} xywh {5 60 18 18} box DIAMOND_DOWN_BOX color 50 labelfont 13 align 24 + } + Fl_Output txtState { + label Disconnecting + xywh {27 57 483 24} box FLAT_BOX color 50 align 20 resizable + code0 {o->type(FL_NORMAL_OUTPUT);} + class Fl_Input2 + } + } + } + Fl_Text_Display txtARQ { + xywh {0 87 515 117} box DOWN_BOX textfont 4 resizable + } + Fl_Group {} {open + xywh {0 206 516 26} box DOWN_BOX + } { + Fl_Output txtStatus { + tooltip {Status messages} xywh {5 208 220 22} align 20 resizable + code0 {o->type(FL_NORMAL_OUTPUT);} + class Fl_Input2 + } + Fl_Output txtStatus2 {selected + xywh {225 208 170 22} align 20 + code0 {o->type(FL_NORMAL_OUTPUT);} + class Fl_Input2 + } + Fl_Progress prgStatus { + tooltip {Tx/Rx ARQ file transfer progress} xywh {395 210 70 18} selection_color 70 labelfont 1 + code0 {o->minimum(0.0);} + code1 {o->maximum(1.0);} + } + Fl_Button btnClearText { + label Clear + callback {cbClearText();} + xywh {468 210 45 20} + } + } + Fl_Group {} { + label {Plain Talk} open + xywh {0 235 515 180} box ENGRAVED_FRAME align 21 + } { + Fl_Text_Display txtRX { + xywh {5 255 505 130} box DOWN_BOX textfont 4 resizable + } + Fl_Group {} {open + xywh {0 387 515 28} box ENGRAVED_FRAME + } { + Fl_Input txtTX { + label {input:} + callback {cbSendTalk();} + tooltip {Plain talk text - ENTER to send} xywh {5 390 450 22} align 0 when 8 resizable + code0 {txtTX->value("");} + code1 {txtTX->maximum_size(80);} + class Fl_Input2 + } + Fl_Button btnSendTalk { + label Clear + callback {cbClearTalk();} + xywh {460 390 49 22} + } + } + } + } +} + +Function {arq_configure()} {} { + Fl_Window {} { + label {Configure flarq} open + xywh {519 621 610 195} type Double hide resizable + } { + Fl_Group {} {open + xywh {2 2 190 166} box ENGRAVED_FRAME + } { + Fl_Input txtMyCall { + label {My Call:} + callback {changeMyCall(o->value());} + xywh {5 22 100 24} align 5 + code0 {o->value(MyCall.c_str());} + class Fl_Input2 + } + Fl_Group {} { + label {Text/Binary Files} open + xywh {2 60 190 105} box ENGRAVED_FRAME align 17 + } { + Fl_Input txtFolder { + label {In folder:} + callback {InFolder = o->value();} + tooltip {Folder (in $HOME) to store incoming files} xywh {6 96 180 24} align 5 when 1 + code0 {o->value(InFolder.c_str());} + class Fl_Input2 + } + Fl_Input txtOutputFolder { + label {Out folder:} + callback {OutFolder = o->value();} + tooltip {Folder (in $HOME) to store outgoing files} xywh {6 138 180 24} align 5 when 1 + code0 {o->value(OutFolder.c_str());} + class Fl_Input2 + } + } + } + Fl_Group {} { + label {Mail Client Files} open + xywh {194 3 190 164} box ENGRAVED_FRAME align 17 + } { + Fl_Input txtMail_IN { + label {Mail In:} + callback {MailInFolder = o->value();} + tooltip {Folder to store incoming files} xywh {200 37 178 24} align 5 when 1 + code0 {o->value(MailInFolder.c_str());} + class Fl_Input2 + } + Fl_Input txtMail_OUT { + label {Mail Out:} + callback {MailOutFolder = o->value();} + tooltip {Folder to store outgoing files} xywh {200 78 178 24} align 5 when 1 + code0 {o->value(MailOutFolder.c_str());} + class Fl_Input2 + } + Fl_Input txtMail_SENT { + label {Mail Sent:} + callback {MailSentFolder = o->value();} + tooltip {Folder to store outgoing files} xywh {200 119 178 24} align 5 when 1 + code0 {o->value(MailSentFolder.c_str());} + class Fl_Input2 + } + Fl_Check_Button btnSylpheedMail { + label {Sylpheed Mail Client} + callback {bSylpheedFolder = o->value();} + tooltip {Check ONLY if Sylpheed is used as mail client} xywh {200 146 175 15} down_box DOWN_BOX + code0 {o->value(bSylpheedFolder);} + } + } + Fl_Group {} {open + xywh {386 3 224 163} box ENGRAVED_FRAME + } { + Fl_Spinner spnExponent { + label {Exponent:} + callback {exponent = (int)o->value(); +switch (exponent) { +case 4: txtBlockSize->value("16"); break; +case 5: txtBlockSize->value("32"); break; +case 6: txtBlockSize->value("64"); break; +case 7: txtBlockSize->value("128"); break; +case 8: txtBlockSize->value("256"); break; +default: +txtBlockSize->value("32");break; +} +cbSetConfig();} + tooltip {block size = 2^exponent} xywh {464 138 30 22} value 1 + code0 {o->minimum(4);} + code1 {o->maximum(8);} + code2 {o->step(1);} + code3 {o->value(exponent);} + } + Fl_Spinner spnRetries { + label {Retries:} + callback {iretries = (int)o->value(); +cbSetConfig();} + tooltip {\# retries before connection declared down} xywh {558 7 45 22} value 1 + code0 {o->minimum(2);} + code1 {o->maximum(20);} + code2 {o->step(1);} + code3 {o->value(iretries);} + } + Fl_Spinner spnWaitTime { + label {Wait time (sec):} + callback {iwaittime = (int)(1000 * o->value()); +cbSetConfig();} + tooltip {time between retries} xywh {533 33 70 22} value 1 + code0 {o->minimum(10);} + code1 {o->maximum(30);} + code2 {o->step(5);} + code3 {o->value(iwaittime/1000);} + } + Fl_Spinner spnTimeout { + label {Timeout (sec):} + callback {itimeout = (int)(o->value() * 1000.0); +cbSetConfig();} + tooltip {Time out for dead connection} xywh {533 59 70 22} value 1 + code0 {o->minimum(30);} + code1 {o->maximum(300);} + code2 {o->step(15);} + code3 {o->value(itimeout / 1000);} + } + Fl_Spinner spnTxDelay { + label {Tx delay (msec):} + callback {txdelay = (int)o->value(); +cbSetConfig();} + tooltip {delay from Rx to Tx} xywh {533 85 70 22} value 1 + code0 {o->minimum(200);} + code1 {o->maximum(2000);} + code2 {o->step(100);} + code3 {o->value(txdelay);} + } + Fl_Spinner spnBcnInterval { + label {Beacon interval (sec)} + callback {bcnInterval = (int)o->value(); +cbSetConfig();} + tooltip {Time between beacon transmissions} xywh {554 111 49 22} value 1 + code0 {o->minimum(15); o->maximum(600);} + code1 {o->step(15);} + code2 {o->value(bcnInterval);} + } + Fl_Output txtBlockSize { + label { = Blk Size} + xywh {568 137 35 24} + code0 {switch (exponent) { +case 4: o->value("16"); break; +case 5: o->value("32"); break; +case 6: o->value("64"); break; +case 7: o->value("128"); break; +default: +o->value("32");break; +} +o->type(FL_NORMAL_OUTPUT); +} + class Fl_Input2 + } + } + Fl_Button btnOK { + label Ok + callback {closeConfig();} + xywh {540 169 62 24} + } + Fl_Input txtBEACONTXT { + label {Beacon Text} + callback {changeBeaconText(o->value());} + tooltip {Text for the beacon 64 chars max} xywh {90 168 443 24} resizable + code0 {o->value(beacontext.c_str());} + class Fl_Input2 + } + } +} + +Function {arq_SendSelect()} {open +} { + Fl_Window {} { + label {Select Email} open + xywh {427 717 500 170} type Double resizable modal visible + } { + Fl_Box tblOutgoing { + xywh {0 3 500 140} box DOWN_BOX color 7 selection_color 246 align 16 + code0 {\#include "table.h"} + class Table + } + Fl_Button send_Cancel { + label Cancel + callback {sendCancel();} + xywh {335 145 70 20} + code0 {extern void sendCancel();} + } + Fl_Return_Button send_OK { + label OK + callback {sendOK();} + xywh {420 145 72 20} + code0 {extern void sendOK();} + } + } +} + +Function {arq_composer()} {open +} { + Fl_Window {} { + label {Flarq Mail Composer} open + xywh {575 537 515 275} type Double resizable visible + } { + Fl_Input inpMailTo { + label {To:} + xywh {48 4 460 24} + class Fl_Input2 + } + Fl_Input inpMailSubj { + label {Subj:} + xywh {48 30 460 24} + class Fl_Input2 + } + Fl_Text_Editor txtMailText { + xywh {0 56 510 188} resizable + } + Fl_Pack {} {open + xywh {0 247 515 28} type HORIZONTAL + } { + Fl_Button btnOpenComposedMail { + label Open + callback {cb_OpenComposeMail();} + tooltip {Open existing Composed email} xywh {4 251 70 20} + code0 {extern void cb_OpenComposeMail();} + } + Fl_Box {} { + xywh {75 251 5 20} + } + Fl_Button btnClearComposer { + label Clear + callback {cb_ClearComposer();} + tooltip {Clear all fields} xywh {81 251 70 20} + code0 {extern void cb_ClearComposer();} + } + Fl_Box {} { + xywh {152 251 5 20} + } + Fl_Button btnUseTemplate { + label Template + callback {cb_UseTemplate();} + tooltip {Use template file} xywh {159 251 70 20} + code0 {extern void cb_UseTemplate();} + } + Fl_Box {} { + xywh {230 251 127 20} resizable + } + Fl_Button btnCancelComposedMail { + label Cancel + callback {cb_CancelComposeMail();} + tooltip {Close Dialog} xywh {358 251 70 20} + code0 {extern void cb_CancelComposeMail();} + } + Fl_Box {} { + xywh {429 251 5 20} + } + Fl_Button btnSaveComposedMail { + label Save + callback {cb_SaveComposeMail();} + tooltip {Save this message (shift click Save Template)} xywh {436 251 70 20} + code0 {extern void cb_SaveComposeMail();} + } + } + } +} diff --git a/src/flarq-src/arqhelp.cxx b/src/flarq-src/arqhelp.cxx new file mode 100644 index 00000000..3e25aead --- /dev/null +++ b/src/flarq-src/arqhelp.cxx @@ -0,0 +1,183 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __WOE32__ + #include + #include + #include +#endif + +#include "flarq.h" +#include "arq.h" +#include "arqdialogs.h" +#include "b64.h" + +Fl_Help_Dialog *help_dialog = (Fl_Help_Dialog *)0; + +void help_cb() { + if (!help_dialog) { + help_dialog = new Fl_Help_Dialog(); + + help_dialog->value( + "\n" + "\n" + "Flarq Help\n" + "\n" + "\n" + +"

Initiating an ARQ connect session

\n" + +"

Start by sending a 'CQ NBEMS' or some similar unique way of indicating\n" +"that you are seeking to send ARQ traffic. Do this from the digital modem\n" +"program and not from flarq. The potential station for receiving your ARQ\n" +"traffic will answer in the clear. Negotiate what digital mode you will use\n" +"for the ARQ connection; ie: PSK-63, PSK-125, PSK-250, MFKS-16 etc. Then\n" +"try that mode without ARQ to be sure that QRN and QSB will not seriously\n" +"disrupt the connection. Ask the responding station to send an ARQ beacon\n" +"using flarq. You will then see his ARQ callsign appear in the callsign\n" +"window.

" + +"

Click the CONNECT button to connect with that station. The text next to\n" +"the diamond will change to CONNECTING and remain that way during the connect\n" +"time out period. During the connection process the CONNECT button will be\n" +"disabled (greyed out).

\n" + +"

After a connection has been established the button label changes to\n" +"'Disconnect' and the text next to the diamond indicator will read CONNECTED.\n" +"Pressing this button will then execute an orderly disconnect from the other\n" +"station and return the program to the CONNECTED state.

\n" + +"

During a file transfer the button's label changes to Abort. When the\n" +"button says Abort, pressing it will abort the file transfer and the program\n" +"will return to the CONNECTED state. During the abort text next to the\n" +"diamond indicator will read ABORTING XFR and return to CONNECTED after the\n" +"abort has been fully recognized by both ends of the connection.

\n" + +"

Beaconing

\n" + +"

Click the Beacon button to transmit a beacon signal requesting\n" +"assistance with ARQ message forwarding. The small rectangle on the Beacon\n" +"button will turn green when a beacon signal is being sent. The beacon will\n" +"repeat at the repeat interval (default is 60 seconds). You should not reduce\n" +"the repeat interval so short as to make it impossible to receive an ARQ\n" +"connection. This is particularly true on PSK-31.

\n" + +"

Diamond Indicator

\n" + +"

The diamond-shaped indicator will be green when ready to transfer messages.\n" +"The ""Not Connected"" label next to the diamond indicator will change to Sending\n" +"when sending, or Connected when connected.

\n" + +"

Send Menu

\n" + +"

The Send menu will not be enabled unless a CONNECTION has been established\n" +"with another flarq station.

\n" + +"

This menu accesses four types of files. When selecting any type, the Show: field\n" +"allows you to use the dropdown arrow to choose which type of file to display.

\n" + +"

The area with the question mark is where file content is displayed, if the Preview\n" +"box is checked.

\n" + +"

The Filename field has a row of buttons above it which can be used to quickly\n" +"navigate through the hierarchy of folders shown. Just click the button over the\n" +"folder you want to access.

\n" + +"

When Email is selected, a list of emails waiting to be transferred will be\n" +"displayed. Select an email and click the Send button to start transferring the\n" +"email.

\n" + +"

When Image File is selected, Flarq can send a color, passport photo sized\n" +"picture, in about 10 minutes using PSK250.

\n" + +"

Config Menu

\n" + +"

This menu provides a place where you should enter your callsign that Flarq\n" +"will use for transmitting. Various folders are shown and can be changed, but\n" +"it is recommended that the default folders be used except in special\n" +"circumstances.

\n" + +"

If you are using the Sylpheed mail client you need to check that box.\n" +"Sylpheed uses a different naming convention for storing messages inside of\n" +"it's mail folders.

\n" + +"

The beacon interval is probably the most often changed setting. Use it to\n" +"control how often Flarq sends the beacon text.

\n" + +"

You can enter additional beacon text which will be sent with the each time\n" +"the ARQ beacon is transmited.

\n" + +"

At the bottom left of the Flarq window there is a space on the left side that\n" +"displays messages showing the Flarq status at any given time.

\n" + +"

At the bottom right, there is a space for a progress indicator, which will show\n" +"a moving green bar as a message is transferred. When a transfer is completed, the\n" +"green color will disappear after filling the space, indicating that transfer has\n" +"been completed.

\n" + +"

Status Bar

\n" + +"

A notification area in the bar just above the Plain Talk label will show the name\n" +"and size of the file being transferred and how long it took to transfer when the\n" +"transfer is completed. The left and right arrows are for adjusting the number of\n" +"SOH characters preceeding each block. Leave it at the default of 10 unless you\n" +"have trouble connecting at high speed, or have too many repeat blocks. Then try\n" +"higher values to reduce the number of repeated blocks.

\n" + +"

Next to the right hand arrow is an area where the quality level of the transfer\n" +"is shown. A transfer without any retries will be shown as 1.00.

\n" + +"

The area next to the Clear button will display a progress indicator, which will\n" +"show the progress of the transfer. When you are sending a message, it will show\n" +"the amount of the message confirmed as being received correctly. When you are on\n" +"the receiving end, it will advance as each message frame is received.

\n" + +"

The Clear button can be used to clear the flarq screen.

\n" + +"

Plain Talk

\n" + +"

You can also communicate during, before, or after a file transfer, as long as\n" +"the Connected diamond is green (showing that you are connected to the other\n" +"station), by typing in the box next to the Clear button at the very bottom of\n" +"the flarq window, and pressing Enter. The text you are sending will be shown\n" +"in red in the Plain Talk window and incoming text from the other station will\n" +"be shown in black. Text you type will be sent out at the first opportunity,\n" +"but only after a block completes being sent, so there will be a delay until\n" +"your text appears on the other station's Plain Talk window, and the other\n" +"station responds. As with most edit controls it is necessary to first put\n" +"the keyboard focus in that box by clicking in it with the mouse.

\n" + +"

The maximum number of characters you can type on the Plain Talk line before\n" +"pressing Enter can be no more than 80 characters. In order to make the speed\n" +"of Plain Talk text exchanges as rapid as possible, Plain Talk uses the current\n" +"mode without any ARQ error checking, so there may be some errors at the\n" +"receiving end that would not occur if ARQ were used.

\n" + +"

The Clear button next to the Plain Talk line can be used to clear the Plain\n" +"Talk display area." + +"\n" + ); + } + + help_dialog->show(); +} + diff --git a/src/flarq-src/b64.cxx b/src/flarq-src/b64.cxx new file mode 100644 index 00000000..12b0724c --- /dev/null +++ b/src/flarq-src/b64.cxx @@ -0,0 +1,225 @@ +//===================================================================== +// +// base64 encoding / decoding class +// +// To create a standalone base64 encode/coder: +// g++ -DTEST b64.cxx -o base64 +// +// To use in a calling program: +// +// base64 b64; // default no CRLF's in output file +// base 64 b64(true); // insert CRLF's in output file +// pass c++ string into encoder / decoder +// return value is encoded / decoded string +// original string is left unchanged +// +// string instr, outstr; +// outstr = b64.encoder(instr); +// outstr = b64.decoder(instr); +//===================================================================== + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "b64.h" + +void base64::init() +{ + iolen = 0; + iocp = 0; + ateof = false; + linelength = 0; + +// create the etable for encoding + for (int i = 0; i < 9; i++) { + etable[i] = 'A' + i; + etable[i + 9] = 'J' + i; + etable[26 + i] = 'a' + i; + etable[26 + i + 9] = 'j' + i; + } + for (int i = 0; i < 8; i++) { + etable[i + 18] = 'S' + i; + etable[26 + i + 18] = 's' + i; + } + for (int i = 0; i < 10; i++) + etable[52 + i] = '0' + i; + etable[62] = '+'; + etable[63] = '/'; + +// create the dtable for decoding + for (int i= 0; i < 255; i++) + dtable[i] = 0x80; + for (int i = 'A'; i <= 'I'; i++) + dtable[i] = 0 + (i - 'A'); + for (int i = 'J'; i <= 'R'; i++) + dtable[i] = 9 + (i - 'J'); + for (int i = 'S'; i <= 'Z'; i++) + dtable[i] = 18 + (i - 'S'); + for (int i = 'a'; i <= 'i'; i++) + dtable[i] = 26 + (i - 'a'); + for (int i = 'j'; i <= 'r'; i++) + dtable[i] = 35 + (i - 'j'); + for (int i = 's'; i <= 'z'; i++) + dtable[i] = 44 + (i - 's'); + for (int i = '0'; i <= '9'; i++) + dtable[i] = 52 + (i - '0'); + dtable[(int)'+'] = 62; + dtable[(int)'/'] = 63; + dtable[(int)'='] = 0; +} + +string base64::encode(string in) +{ + int n; + byte igroup[3], ogroup[4]; + + output = ""; + iocp = 0; + ateof = false; + if (crlf) + linelength = 0; + iolen = in.length(); + + while (!ateof) { + igroup[0] = igroup[1] = igroup[2] = 0; + for (n = 0; n < 3; n++) { + if (iocp == iolen) { + ateof = true; + break; + } + igroup[n] = (byte)in[iocp]; + iocp++; + } + if (n > 0) { + ogroup[0] = etable[igroup[0] >> 2]; + ogroup[1] = etable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)]; + ogroup[2] = etable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)]; + ogroup[3] = etable[igroup[2] & 0x3F]; + if (n < 2) { + ogroup[2] = '='; + if (n < 1) { + ogroup[2] = '='; + } + } + for (int i = 0; i < 4; i++) { + if (crlf) + if (linelength >= LINELEN) { +// output += '\r'; + output += '\n'; + linelength = 0; + } + output += (byte)ogroup[i]; + if (crlf) + linelength++; + } + } + } + if (crlf) { +// output += '\r'; + output += '\n'; + } + + return output; +} + +string base64::decode(string in) +{ + int i; + output = ""; + iocp = 0; + iolen = in.length(); + byte c; + + while (iocp < iolen) { + byte a[4], b[4], o[3]; + + for (i = 0; i < 4; i++) { + if (iocp == iolen) { + output = "b64 file length error.\n"; + return output; + } + c = in[iocp++]; + while (c <= ' ') { + if (iocp == iolen) { + return output; + } + c = in[iocp++]; + } + if (dtable[c] & 0x80) { + output = "Illegal character in b64 file.\n"; + return output; + } + a[i] = c; + b[i] = (byte)dtable[c]; + } + o[0] = (b[0] << 2) | (b[1] >> 4); + o[1] = (b[1] << 4) | (b[2] >> 2); + o[2] = (b[2] << 6) | b[3]; + output += o[0]; + if (a[2] != '=') { + output += o[1]; + if (a[3] != '=') + output += o[2]; + } + } + return output; +} + +#ifdef TEST +#include +#include + + +void usage(void) +{ + printf("b64 -- Encode/decode file as base64. Call:\n"); + printf(" b64 e/d < infile > outfile\n"); +} + +int main(int argc,char*argv[]) +{ + char opt; + bool decoding = false; + char * cp; + byte c; + + string inputstring; + string infilename; + string outputstring; + string outfilename; + + base64 b64; + + if (argc < 2) { + usage(); + return(0); + } + opt = *(argv[1]); + + if (opt == 'd' || opt == 'D') { + while (!std::cin.eof()) { + c = std::cin.get(); + if (!std::cin.eof()) + inputstring += c; + } + outputstring = b64.decode( inputstring ); + size_t len = outputstring.length(); + for (size_t n = 0; n < len; n++) + std::cout << (unsigned char)outputstring[n]; + } else if (opt == 'e' || opt == 'E') { + while (!std::cin.eof()) { + c = std::cin.get(); + if (!std::cin.eof()) + inputstring += c; + } + outputstring = b64.encode( inputstring ); + size_t len = outputstring.length(); + for (size_t n = 0; n < len; n++) + std::cout << (unsigned char)outputstring[n]; + } else + usage(); + + return 0; +} +#endif diff --git a/src/flarq-src/flarq.cxx b/src/flarq-src/flarq.cxx new file mode 100644 index 00000000..6660e147 --- /dev/null +++ b/src/flarq-src/flarq.cxx @@ -0,0 +1,1924 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __MINGW32__ +# include "compat.h" +#endif + +#ifdef __MINGW32__ +# define dirent fl_dirent_no_thanks +#endif +#include +#ifdef __MINGW32__ +# undef dirent +#endif + +#include "fileselect.h" + +#include "socket.h" + +#include + +#include "flarq.h" +#include "flarqenv.h" +#include "flmisc.h" +#include "stacktrace.h" +#include "icons.h" +#include "arq.h" +#include "arqdialogs.h" +#include "b64.h" + +#define FLDIGI_port "7322" +#define MPSK_port "3122" + +#define MPSK_TX "TX" +#define MPSK_RX "RX" +#define MPSK_TX2RX "RX_AFTER_TX" +#define MPSK_BYTE 25 +#define MPSK_CMD 26 +#define MPSK_END 27 +#define MPSK_ISTX 28 +#define MPSK_ISRX 29 +#define MPSK_ISCMD 30 +#define MPSK_CMDEND 31 + +bool SHOWDEBUG = false; + +extern void STATUSprint(string s); + +Fl_Text_Buffer *txtbuffARQ; +Fl_Text_Buffer *stylebufARQ; +Fl_Text_Buffer *txtbuffRX; +Fl_Text_Buffer *stylebufRX; +Fl_Text_Buffer *txtbuffComposer; +//Fl_Text_Buffer *styleComposer; + +Fl_Text_Display::Style_Table_Entry styletable[] = { // Style table + { FL_BLACK, FL_SCREEN, FL_NORMAL_SIZE }, // A - RX + { FL_DARK_RED, FL_SCREEN, FL_NORMAL_SIZE }, // B - TX + { FL_DARK_GREEN, FL_SCREEN, FL_NORMAL_SIZE }, // C - DEBUG rx text + { FL_MAGENTA, FL_SCREEN, FL_NORMAL_SIZE } // D - DEBUG tx text +}; + +Fl_Double_Window *arqwin = 0; +Fl_Double_Window *dlgconfig = 0; +Fl_Double_Window *outdialog = 0; +Fl_Double_Window *composer = 0; + +using namespace std; + +arq *digi_arq; +bool traffic = false; +bool sendingfile = false; +int arqstate = 0; +bool configured = false; + +bool ioMPSK = false; +string arq_address = "127.0.0.1"; +string arq_port = FLDIGI_port; + +string RX; +string TX; + +string teststring; + +string statusmsg; + +string MyCall; +string beacontext; + +#ifdef __WOE32__ + +char szHomedir[120] = "c:/NBEMS"; +string str_homedir = "c:/NBEMS"; +string str_arqlog = "ARQXFR/arqlog.txt"; +string MailFolder = "Mail"; +string MailInFolder = "Mail/ARQin"; +string MailOutFolder = "Mail/ARQout"; +string MailSentFolder = "Mail/ARQsent"; +string InFolder = "ARQrecv"; +string OutFolder = "ARQsend"; +string MailFileName = ""; +string MailSaveFileName = ""; +bool bSylpheedFolder = false; +bool SendingEmail = false; +struct dirent *entry; +DIR *dp; + +#else + +char szHomedir[120]; +string str_arqlog = "ARQfiles/logfile.txt"; +string MailFolder = "Mail"; +string MailInFolder = "Mail/ARQin"; +string MailOutFolder = "Mail/ARQout"; +string MailSentFolder = "Mail/ARQsent"; +string InFolder = "ARQrecv"; +string OutFolder = "ARQsend"; +string ARQFolder = "ARQfiles"; +string MailFileName = ""; +string MailSaveFileName = ""; +bool bSylpheedFolder = true; +bool SendingEmail = false; +struct dirent *entry; +DIR *dp; + +#endif + +string Logfile; + +#if !defined(__APPLE__) && !defined(__WOE32__) +Pixmap flarq_icon_pixmap; +#endif + +Socket *tcpip = 0; +string txbuffer; +string cmdbuffer; +string rxbuffer; + +size_t bufsize = 0; +size_t bufptr = 0; + +bool isRxChar = false; +bool isCmdChar = false; +bool isTxChar = false; +bool inLoop = false; + +int exponent = 7; +int txdelay = 500; +int iretries = 5; +long iwaittime = 10000; +long itimeout = 60000; +int bcnInterval = 30; +bool autobeacon = false; +bool beaconrcvd = false; + +int blocksSent = 0; + +int mainX = 0, mainY = 0, mainW = 600, mainH = 500; + +float vers = 0; +float version; + +const char *ASCII[32] = { + "", "", "", "", // 0x00 - 0x03 + "", "", "", "", // 0x04 - 0x07 + "", "", "", "", // 0x08 - 0x0B + "", "", "", "", // 0x0C - 0x0F + "", "", "", "", // 0x10 - 0x13 + "", "", "", "", // 0x14 - 0x17 + "", "", "", "", // 0x18 - 0x1B + "", "", "", "" // 0x1C - 0x1F +}; + +string AsciiChars; + +string incomingText = ""; +string txtarqload = ""; +string rxfname = ""; +string arqstart = "ARQ::STX\n"; +string arqend = "ARQ::ETX\n"; +string arqfile = "ARQ:FILE::"; +string arqemail = "ARQ:EMAIL::\n"; +string arqascii = "ARQ:ENCODING::ASCII\n"; +string arqbase64 = "ARQ:ENCODING::BASE64\n"; +string arqsizespec = "ARQ:SIZE::"; +size_t startpos = string::npos; +size_t endpos = string::npos; +size_t fnamepos = string::npos; +size_t indx = string::npos; +size_t sizepos = string::npos; +size_t lfpos = string::npos; +size_t arqPayloadSize = 0; +bool haveemail = false; +bool rxARQfile = false; +bool rxARQhavesize = false; +bool rxTextReady = false; + +time_t StartTime_t; +time_t EndTime_t; +time_t TransferTime_t; +double TransferTime; + +//============================================================================= +// email selector +//============================================================================= + +int datedir = 1; +int todir = 1; +int subdir = 1; +string sendfilename = ""; + +void cb_SortByDate() +{ + if (datedir == 0) { + tblOutgoing->sort(1, false); + datedir = 1; + } else { + tblOutgoing->sort(1, true); + datedir = 0; + } + tblOutgoing->redraw(); +} + +void cb_SortByTo() +{ + if (todir == 0) { + tblOutgoing->sort(2, false); + todir = 1; + } else { + tblOutgoing->sort(2, true); + todir = 0; + } + tblOutgoing->redraw(); +} + +void cb_SortBySubj() +{ + if (subdir == 0) { + tblOutgoing->sort(3, false); + subdir = 1; + } else { + tblOutgoing->sort(3, true); + subdir = 0; + } + tblOutgoing->redraw(); +} + +void sendOK() +{ + outdialog->hide(); + int sel = tblOutgoing->value(); + if (sel >= 0) + sendfilename = tblOutgoing->valueAt(sel,0); + else + sendfilename.clear(); +} + +void sendCancel() +{ + outdialog->hide(); + sendfilename.clear(); +} + +void selectTrafficOut(bool ComposerOnly) +{ + if (outdialog == 0) { + outdialog = arq_SendSelect(); + outdialog->xclass(PACKAGE_TARNAME); + tblOutgoing->addHiddenColumn ("fnbr"); // column #0 + tblOutgoing->addColumn ("Date", 180); // column #1 + tblOutgoing->addColumn ("To", 120); // column #2 + tblOutgoing->addColumn ("Subj", 196); // column #3 + tblOutgoing->colcallback (1, cb_SortByDate); + tblOutgoing->columnAlign(1, FL_ALIGN_LEFT); + tblOutgoing->colcallback (2, cb_SortByTo); + tblOutgoing->columnAlign(2, FL_ALIGN_LEFT); + tblOutgoing->colcallback (3, cb_SortBySubj); + tblOutgoing->columnAlign(3, FL_ALIGN_LEFT); + tblOutgoing->allowSort(true); + tblOutgoing->rowSize (20); + tblOutgoing->headerSize (20); + tblOutgoing->allowResize (true); + tblOutgoing->gridEnabled (true); + } + tblOutgoing->clear(); + string fline, fname, fdate, fto, fsubj; + char szline[10000]; + size_t p; + string folder = szHomedir; + folder += '/'; + folder.append(MailOutFolder); + dp = 0; + dp = opendir(folder.c_str()); + if (dp == 0) { + string nfound = folder; + nfound += " not found"; + fl_alert2(nfound.c_str()); + return; + } + folder += '/'; + int nummails = 0; + while ((entry = readdir(dp)) != 0) { + if (entry->d_name[0] == '.') + continue; + fname = folder; fname.append(entry->d_name); +#ifdef __WOE32__ + if (fname.find(".eml") == string::npos) + continue; +#endif + int validlines = 0; + ifstream emailtxt(fname.c_str()); + while (!emailtxt.eof()) { + memset(szline, 0, 10000); + emailtxt.getline(szline,10000); + fline = szline; + if ((p = fline.find("Date: ")) != string::npos) { + fdate = fline.substr(p + 6); + validlines++; + continue; + } + if ((p = fline.find("To: ")) != string::npos) { + fto = fline.substr(p + 4); + p = fto.find('@'); + if (p != string::npos) fto.replace(p,1,"@@"); + p = fto.find("<"); + if (p != string::npos) fto.erase(p,1); + p = fto.find(">"); + if (p != string::npos) fto.erase(p,1); + validlines++; + continue; + } + if ((p = fline.find("Subject: ")) != string::npos) { + fsubj = fline.substr(p + 9); + validlines++; + continue; + } + if ((p = fline.find("//FLARQ COMPOSER")) != string::npos) + validlines++; + } + emailtxt.close(); + if ((!ComposerOnly && validlines >= 3) || (ComposerOnly && validlines == 4)) { + tblOutgoing->addRow (4, fname.c_str(), fdate.c_str(), fto.c_str(), fsubj.c_str()); + nummails++; + } + } + if (nummails) { + tblOutgoing->FirstRow(); + outdialog->show(); + while (outdialog->shown()) + Fl::wait(); + } else + fl_message2("No emails for delivery"); +} + +//====================================================================================== +// simple email composer +//====================================================================================== +extern bool fileExists(string fname); + +void cb_CancelComposeMail() +{ + composer->hide(); +} + +void readComposedFile(string filename) +{ + ifstream textfile; + textfile.open(filename.c_str()); + if (textfile) { + char szline[10000]; + string fline, tempstr; + size_t p; + txtbuffComposer->text(""); + while (!textfile.eof()) { + memset(szline,0, 10000); + textfile.getline(szline,10000); + fline = szline; + if ((p = fline.find("//FLARQ COMPOSER")) != string::npos) continue; + if ((p = fline.find("Date: ")) != string::npos) continue; + if ((p = fline.find("From:")) != string::npos) continue; + if ((p = fline.find("To: ")) != string::npos) { + tempstr = fline.substr(p + 4); + p = tempstr.find("<"); + if (p != string::npos) tempstr.erase(p,1); + p = tempstr.find(">"); + if (p != string::npos) tempstr.erase(p,1); + inpMailTo->value(tempstr.c_str()); + continue; + } + if ((p = fline.find("Subject: ")) != string::npos) { + inpMailSubj->value(fline.substr(p + 9).c_str()); + continue; + } + if (strlen(szline) == 0 && txtbuffComposer->length() == 0) continue; + txtbuffComposer->append(szline); + txtbuffComposer->append("\n"); + } + textfile.close(); + } +} + +void cb_UseTemplate() +{ + string templatename = szHomedir; + templatename += '/'; + templatename.append(MailOutFolder); + templatename += '/'; + const char *p = FSEL::select("Load Template file", "*.tpl", templatename.c_str()); + if (p) + readComposedFile(p); +} + +void cb_ClearComposer() +{ + sendfilename.clear(); + txtbuffComposer->text(""); + inpMailTo->value(""); + inpMailSubj->value(""); +} + +string nextEmailFile(string fname) +{ + int nbr = 0; + char szNbr[20]; + string name; + string ext; + string nuname; + size_t p; + + p = fname.find_last_of('.'); + if (p != string::npos) { + ext = fname.substr(p); + name = fname.substr(0,p); + } else { + ext = ""; + name = fname; + } + + do { + nbr++; + nuname = name; +#ifdef __WOE32__ + snprintf(szNbr, sizeof(szNbr), "-%-d", nbr); +#else + snprintf(szNbr, sizeof(szNbr), "%-d", nbr); +#endif + nuname.append(szNbr); + nuname.append(ext); + } while (fileExists(nuname)); + return nuname; +} + +void saveComposedText(string filename) +{ + ofstream textfile; + textfile.open(filename.c_str()); + textfile << "//FLARQ COMPOSER" << endl; + char szmaildt[100]; + time_t maildt = time(NULL); + struct tm *gmt = gmtime(&maildt); + strftime(szmaildt, sizeof(szmaildt), "%x %X", gmt); + textfile << "Date: " << szmaildt << endl; + textfile << "To: " << inpMailTo->value() << endl; + textfile << "From: " << endl; + textfile << "Subject: " << inpMailSubj->value() << endl; + textfile << endl << txtbuffComposer->text() << endl; + textfile.close(); + cb_ClearComposer(); +} + +void SaveComposeMail() +{ + if (strlen(inpMailTo->value()) == 0 || + strlen(inpMailSubj->value()) == 0) + return; + if (sendfilename.empty()) { + sendfilename = szHomedir; + sendfilename += '/'; + sendfilename += MailOutFolder; +#ifdef __WOE32__ + sendfilename += "/flarqmail.eml"; +#else + sendfilename += "/"; +#endif + sendfilename = nextEmailFile(sendfilename); + } + saveComposedText(sendfilename); +} + +void SaveComposeTemplate() +{ + string templatename = szHomedir; + templatename += '/'; + templatename.append(MailOutFolder); + templatename += '/'; + const char *p = FSEL::saveas("Save Template file", "*.tpl", templatename.c_str()); + if (p) + saveComposedText(p); +} + +void cb_SaveComposeMail() +{ + if (Fl::event_state(FL_SHIFT)) + SaveComposeTemplate(); + else + SaveComposeMail(); +} + +void cb_OpenComposeMail() +{ + sendfilename.clear(); + selectTrafficOut(true); + if (sendfilename.empty()) + return; + readComposedFile(sendfilename); +} + +void ComposeMail() +{ + if (composer == 0) { + composer = arq_composer(); + composer->xclass(PACKAGE_TARNAME); + txtbuffComposer = new Fl_Text_Buffer(); + txtMailText->buffer(txtbuffComposer); + txtMailText->wrap_mode(1,80); + } + txtbuffComposer->text(""); + inpMailTo->value(""); + inpMailSubj->value(""); + + composer->show(); +} + +//====================================================================================== + +string noCR(string s) +{ + string text = s; + size_t p; + while ((p = text.find('\r')) != string::npos) + text.erase(p,1); + return text; +} + +void createAsciiChars() +{ + AsciiChars = ""; + AsciiChars += 0x09; // tab + AsciiChars += 0x0A; // lf + AsciiChars += 0x0D; // cr + for (int n = 20; n < 128; n++) AsciiChars += n; +} + +void initVals() +{ + MyCall = "NOCALL"; + exponent = digi_arq->getExponent(); + iretries = digi_arq->getRetries(); + itimeout = digi_arq->getTimeout(); + txdelay = digi_arq->getTxDelay(); + iwaittime = digi_arq->getWaitTime(); + bcnInterval = 30; + beacontext = ""; + cbMenuConfig(); + digi_arq->myCall(MyCall.c_str()); + +} + +void testDirectory(string dir) +{ + string tstdir = szHomedir; + tstdir += '/'; + tstdir.append(dir); + ifstream test(tstdir.c_str()); + if (!test) + mkdir(tstdir.c_str(), 0777); + else + test.close(); +} + +void readConfig() +{ + extern void cbMenuConfig(); + string configfname = szHomedir; +#ifndef __WOE32__ + configfname.append("/.flarq"); +#else + configfname.append("/flarq.config"); +#endif + ifstream configfile(configfname.c_str()); + if (configfile) { + char tempstr[200]; + configfile.getline(tempstr,200); + sscanf(tempstr,"%f", &vers); + if (int(vers*10) != int(version*10)) + initVals(); + else { + configfile >> MyCall; + configfile >> InFolder; + configfile >> OutFolder; + configfile >> MailInFolder; + configfile >> MailOutFolder; + configfile >> MailSentFolder; + configfile >> exponent; + configfile >> txdelay; + configfile >> iretries; + configfile >> iwaittime; + configfile >> itimeout; + configfile >> bcnInterval; + configfile >> mainX; + configfile >> mainY; + configfile >> mainW; + configfile >> mainH; + configfile.ignore(); + configfile.getline(tempstr, 200); + configfile >> bSylpheedFolder; + beacontext = tempstr; + digi_arq->myCall(MyCall.c_str()); + digi_arq->setExponent(exponent); + digi_arq->setRetries(iretries); + digi_arq->setTimeout(itimeout); + digi_arq->setTxDelay(txdelay); + digi_arq->setWaitTime(iwaittime); + } + configfile.close(); + } else + initVals(); + +#ifndef __WOE32__ + testDirectory(ARQFolder); +#endif + testDirectory(InFolder); + testDirectory(OutFolder); + testDirectory(MailFolder); + testDirectory(MailInFolder); + testDirectory(MailOutFolder); + testDirectory(MailSentFolder); + +} + +void saveConfig() +{ + string configfname = szHomedir; +#ifndef __WOE32__ + configfname.append("/.flarq"); +#else + configfname.append("/flarq.config"); +#endif + ofstream configfile(configfname.c_str()); + if (configfile) { + int mainX = arqwin->x(); + int mainY = arqwin->y(); + int mainW = arqwin->w(); + int mainH = arqwin->h(); + configfile << VERSION << endl; + configfile << MyCall << endl; + configfile << InFolder << endl; + configfile << OutFolder << endl; + configfile << MailInFolder << endl; + configfile << MailOutFolder << endl; + configfile << MailSentFolder << endl; + configfile << exponent << endl; + configfile << txdelay << endl; + configfile << iretries << endl; + configfile << iwaittime << endl; + configfile << itimeout << endl; + configfile << bcnInterval << endl; + configfile << mainX << endl; + configfile << mainY << endl; + configfile << mainW << endl; + configfile << mainH << endl; + configfile << beacontext.c_str() << endl; + configfile << bSylpheedFolder; + configfile.close(); + } +} + +void cbSetConfig() +{ + digi_arq->setExponent(exponent); + digi_arq->setRetries(iretries); + digi_arq->setTimeout(itimeout); + digi_arq->setTxDelay(txdelay); + digi_arq->setWaitTime(iwaittime); +} + +void closeConfig() +{ + if (dlgconfig) + dlgconfig->hide(); + cbSetConfig(); +} + +void cbMenuConfig() +{ + if (!dlgconfig) { + dlgconfig = arq_configure(); + dlgconfig->xclass(PACKAGE_TARNAME); + } + dlgconfig->show(); +} + +void cbMenuAbout() +{ + fl_message2("flarq - ARQ client\nversion: %s\nw1hkj@@w1hkj.com", VERSION); +} + +string txhold = ""; + +//============================================================================= + +void mpsk_on() +{ + string s; + s.append(1, MPSK_CMD).append(MPSK_TX).append(1, MPSK_END); + try { + tcpip->send(s); + } + catch (const SocketException& e) { + cerr << e.what() << '\n'; + } +} + +void mpsk_off_after_buffer_sent() +{ + string s; + s.append(1, MPSK_CMD).append(MPSK_TX2RX).append(1, MPSK_END); + try { + tcpip->send(s); + } + catch (const SocketException& e) { + cerr << e.what() << '\n'; + } +} + +void mpsk_off() +{ + string s; + s.append(1, MPSK_CMD).append(MPSK_RX).append(1, MPSK_END); + try { + tcpip->send(s); + } + catch (const SocketException& e) { + cerr << e.what() << '\n'; + } +} + +void MPSK_client_transmit(const string& s) +{ + if (s.empty()) + return; + string tosend; + tosend.reserve(s.length() * 2); + for (size_t i = 0; i < s.length(); i++) + tosend.append(1, MPSK_BYTE).append(1, s[i]); + + try { + mpsk_on(); + tcpip->send(tosend); + mpsk_off_after_buffer_sent(); + } + catch (const SocketException& e) { + cerr << e.what() << '\n'; + } +} + +void MPSK_Socket_rcv_loop(void *) +{ + if (inLoop) Fl::wait(0.1); + inLoop = true; + + char cs; + + try { + while (tcpip->wait(0)) { + tcpip->recv(&cs, 1); + + if (isRxChar) { + rxbuffer += cs; + isRxChar = false; + continue; + } + if (isTxChar) { + if (cs < 28 || cs > 31) + txbuffer += cs; + isTxChar = false; + continue; + } + if (isCmdChar) { + if (cs == MPSK_CMDEND) { + isCmdChar = false; + if (cmdbuffer.find("RX_AFTER_TX OK") != string::npos) { + rxbuffer += 0x06; + cmdbuffer.clear(); + txbuffer.clear(); + } + continue; + } + cmdbuffer += cs; + continue; + } + if (cs == MPSK_ISRX) { + isRxChar = true; + continue; + } + if (cs == MPSK_ISCMD) { + isCmdChar = true; + continue; + } + if (cs == MPSK_ISTX) { + isTxChar = true; + continue; + } + } + } + catch (const SocketException& e) { + cerr << e.what() << '\n'; + } + + inLoop = false; + Fl::add_timeout(0.01, MPSK_Socket_rcv_loop); +} + +//============================================================================= + +void client_transmit(const string& s ) +{ + try { + if (!s.empty()) + tcpip->send(s); + } + catch (const SocketException& e) { + cerr << e.what() << '\n'; + } +} + +void Socket_rcv_loop(void *) +{ + if (inLoop) + Fl::wait(0.1); + inLoop = true; + + try { + tcpip->set_nonblocking(true); + tcpip->recv(rxbuffer); + tcpip->set_nonblocking(false); + } + catch (const SocketException& e) { + cerr << e.what() << '\n'; + } + + inLoop = false; + Fl::add_timeout(0.01, Socket_rcv_loop); +} + +bool client_receive(char &c) +{ + if (inLoop) Fl::wait(0.1); + inLoop = true; + bufsize = rxbuffer.length(); + if (bufsize) { + if (bufptr < bufsize) { + c = rxbuffer[bufptr++]; + inLoop = false; + return true; + } + } + rxbuffer.clear(); + bufsize = 0; + bufptr = 0; + inLoop = false; + return false; +} + +int autobeaconcounter = 0; +char bcnMsg[40]; + +void arqAutoBeacon(void *) +{ + if (autobeacon == true) { + int currstate = digi_arq->state(); + btnCONNECT->deactivate(); + btnCONNECT->redraw(); + if (currstate > 0x7F) { + txtBeaconing->value("Beaconing"); + btnBEACON->deactivate(); + btnBEACON->redraw(); + Fl::repeat_timeout(1.0, arqAutoBeacon); + return; + } else if (currstate == DOWN || currstate == TIMEDOUT) { + if (autobeaconcounter == 0) { + digi_arq->sendBeacon( beacontext ); + autobeaconcounter = bcnInterval; + Fl::repeat_timeout(1.0 + txdelay / 1000.0, arqAutoBeacon); + } else { + snprintf(bcnMsg, sizeof(bcnMsg), "Bcn in: %d sec", autobeaconcounter); + txtBeaconing->value(bcnMsg); + btnBEACON->label("STOP"); + btnBEACON->redraw_label(); + btnBEACON->activate(); + btnBEACON->redraw(); + autobeaconcounter--; + Fl::repeat_timeout(1.0, arqAutoBeacon); + } + return; + } else { + autobeaconcounter = 0; + btnBEACON->value(0); + btnBEACON->label("Beacon"); + btnBEACON->redraw_label(); + btnBEACON->activate(); + btnBEACON->redraw(); + txtBeaconing->value("Beacon Off"); + } + } else { + autobeaconcounter = 0; + btnCONNECT->activate(); + btnCONNECT->redraw(); + btnBEACON->value(0); + btnBEACON->label("Beacon"); + btnBEACON->redraw_label(); + btnBEACON->activate(); + btnBEACON->redraw(); + txtBeaconing->value("Beacon Off"); + } +} + +void arqBEACON() +{ + if (autobeacon == false) { + autobeacon = true; + Fl::add_timeout(0.01, arqAutoBeacon); + } else { + autobeacon = false; + } +} + +void printstring(string s) +{ + for (size_t n = 0; n < s.length(); n++) + if (s[n] < ' ') printf("<%02d>",(int)s[n]); + else printf("%c", s[n]); + printf("\n"); +} + +void arqCLOSE() +{ + tcpip->close(); + saveConfig(); + exit(0); +} + +void clearText() +{ + txtarqload = ""; + txtbuffARQ->text(""); + txtStatus->value(""); + txtStatus2->value(""); +} + +void restart() +{ + TX.clear(); + rxfname = ""; + rxTextReady = false; + prgStatus->value(0.0); + prgStatus->label(""); + prgStatus->redraw(); + prgStatus->redraw_label(); + rxARQfile = false; + sendingfile = false; + incomingText.clear(); + clearText(); +} + +void arqCONNECT() +{ + if (digi_arq->state() < CONNECTED) { + if (strlen(txtURCALL->value()) > 0) + digi_arq->connect(txtURCALL->value()); + } else { + if (rxARQfile || sendingfile) + abortTransfer(); + else { + restart(); + digi_arq->disconnect(); + txtURCALL->value(""); + } + } +} + +bool fileExists(string fname) +{ + ifstream test(fname.c_str()); + if (test) { + test.close(); + return true; + } + return false; +} + +string nextFileName(string fname) +{ + int nbr = 0; + char szNbr[20]; + string name; + string ext; + string nuname; + size_t p; + + p = fname.find_last_of('.'); + if (p != string::npos) { + ext = fname.substr(p); + name = fname.substr(0,p); + } else { + ext = ""; + name = fname; + } + + do { + nbr++; + nuname = name; + snprintf(szNbr, sizeof(szNbr), ".dup%-d", nbr); + nuname.append(szNbr); + nuname.append(ext); + } while (fileExists(nuname)); + + return nuname; +} + +void saveEmailFile() +{ + static char xfrmsg[80]; + static char szfnum[10]; + int fnum; + string tempname; + + time(&EndTime_t); + TransferTime = difftime(EndTime_t, StartTime_t); + snprintf(xfrmsg, sizeof(xfrmsg), "Transfer Completed in %4.0f sec's", TransferTime); + + string savetoname = szHomedir; + savetoname += '/'; + savetoname.append(MailInFolder); + savetoname += '/'; + + fnum = 1; + if (bSylpheedFolder) { + tempname = savetoname; + snprintf (szfnum, sizeof(fnum),"%-d", fnum); + tempname += szfnum; + while (fileExists(tempname)) { + fnum++; + tempname = savetoname; + snprintf(szfnum, sizeof(fnum),"%-d", fnum); + tempname += szfnum; + } + savetoname = tempname; + } else { + if (rxfname.find(".eml") == string::npos) + rxfname.append(".eml"); + savetoname.append(rxfname); + while (fileExists(savetoname)) + savetoname = nextFileName(savetoname); + } + + ofstream tfile(savetoname.c_str(), ios::binary); + if (tfile) { + tfile << txtarqload; + tfile.close(); + } + + txtStatus->value(xfrmsg); + rxfname = ""; + txtarqload = ""; + rxTextReady = false; +} + +void saveRxFile() +{ + static char xfrmsg[80]; + time(&EndTime_t); + TransferTime = difftime(EndTime_t, StartTime_t); + snprintf(xfrmsg, sizeof(xfrmsg), "Transfer Completed in %4.0f sec's", TransferTime); + + string savetoname = szHomedir; + savetoname += '/'; + savetoname.append(InFolder); + savetoname += '/'; + savetoname.append(rxfname); + if (fileExists(savetoname)) + savetoname = nextFileName(savetoname); + + ofstream tfile(savetoname.c_str(), ios::binary); + if (tfile) { + tfile << txtarqload; + tfile.close(); + } + + txtStatus->value(xfrmsg); + rxfname = ""; + txtarqload = ""; + rxTextReady = false; +} + +void payloadText(string s) +{ + static char szPercent[10]; + string text = noCR(s); + string style; + + style.append(text.length(), 'A'); + stylebufARQ->append(style.c_str()); + txtARQ->insert(text.c_str()); + txtARQ->show_insert_position(); + txtARQ->redraw(); + + incomingText.append (s); + + if (!rxARQfile) + if ((startpos = incomingText.find(arqstart)) != string::npos) { + rxARQfile = true; + startpos += arqstart.length(); + time(&StartTime_t); + } + if (rxARQfile) { + if (!rxARQhavesize) { + if ( (sizepos = incomingText.find(arqsizespec)) != string::npos) { + sizepos += arqsizespec.length(); + if ((lfpos = incomingText.find('\n', sizepos)) != string::npos) { + string sizechars = incomingText.substr(sizepos, lfpos - sizepos); + sscanf(sizechars.c_str(), "%" PRIuSZ, &arqPayloadSize); + rxARQhavesize = true; + char statusmsg[40]; + snprintf(statusmsg, sizeof(statusmsg), "Rcvg: %" PRIuSZ, arqPayloadSize); + txtStatus->value(statusmsg); + } + } + } else { + if (startpos != string::npos) { + float partial = incomingText.length() - startpos; + snprintf(szPercent, sizeof(szPercent), "%3.0f %%", 100.0 * partial / arqPayloadSize); + prgStatus->value( partial / arqPayloadSize ); + prgStatus->label(szPercent); + } else { + prgStatus->value(0.0); + prgStatus->label(""); + } + prgStatus->redraw(); + prgStatus->redraw_label(); + } + if ((endpos = incomingText.find(arqend)) != string::npos) { + haveemail = false; + fnamepos = incomingText.find(arqfile); + fnamepos += arqfile.length(); + indx = incomingText.find('\n', fnamepos); + rxfname = incomingText.substr(fnamepos, indx - fnamepos); + txtarqload = incomingText.substr(startpos, endpos - startpos); + if (incomingText.find(arqbase64) != string::npos) { + base64 b64; + txtarqload = b64.decode(txtarqload); + } + if (incomingText.find(arqemail) != string::npos) + haveemail = true; + incomingText = ""; + startpos = string::npos; + endpos = string::npos; + fnamepos = string::npos; + indx = string::npos; + sizepos = string::npos; + lfpos = string::npos; + arqPayloadSize = 0; + rxARQfile = false; + rxARQhavesize = false; + rxTextReady = true; + txtStatus->value(""); + prgStatus->value(0.0); + prgStatus->label(""); + prgStatus->redraw(); + prgStatus->redraw_label(); + } + } +} + +void cbClearText() +{ + txtbuffARQ->text(""); +} + +void abortedTransfer() +{ + restart(); + txtARQ->insert("transfer aborted\n"); + btnCONNECT->activate(); +} + +void abortTransfer() +{ + sendingfile = false; + SendingEmail = false; + rxARQfile = false; + btnCONNECT->label("ABORTING"); + btnCONNECT->redraw_label(); + btnCONNECT->deactivate(); + digi_arq->abort(); +} + +void rxBeaconCallsign(string s) +{ + txtURCALL->value(s.c_str()); + beaconrcvd = true; +} + +void moveEmailFile() +{ + static char szfnum[10]; + int fnum = 1; + string tempname; + + if (MailFileName.empty()) return; + if (MailSaveFileName.empty()) return; + + ifstream infile(MailFileName.c_str(), ios::in | ios::binary); + + if (bSylpheedFolder) { + MailSaveFileName = szHomedir; + MailSaveFileName += '/'; + MailSaveFileName.append(MailSentFolder); + MailSaveFileName += '/'; + tempname = MailSaveFileName; + snprintf (szfnum, sizeof(szfnum),"%-d", fnum); + tempname += szfnum; + while (fileExists(tempname)) { + fnum++; + tempname = MailSaveFileName; + snprintf(szfnum, sizeof(fnum),"%-d", fnum); + tempname += szfnum; + } + MailSaveFileName = tempname; + } else { + if (MailSaveFileName.find(".eml") == string::npos) + MailSaveFileName.append(".eml"); + while (fileExists(MailSaveFileName)) + MailSaveFileName = nextFileName(MailSaveFileName); + } + + ofstream outfile(MailSaveFileName.c_str(), ios::out | ios::binary); + char c; + + if (infile && outfile) { + while (!infile.eof()) { + infile.get(c); + outfile.put(c); + } + infile.close(); + outfile.close(); + unlink(MailFileName.c_str()); + } + MailFileName.clear(); + MailSaveFileName.clear(); +} + + +void sendEmailFile() +{ + if (arqstate < CONNECTED) { + fl_alert2("Not connected"); + return; + } + sendfilename.clear(); + selectTrafficOut(false); + + if (sendfilename.empty()) + return; + + char cin; + size_t txtsize; + string textin = ""; + char sizemsg[40]; + size_t p; + + ifstream textfile; + textfile.open(sendfilename.c_str(), ios::binary); + if (textfile) { + MailFileName = sendfilename; + TX.erase(); + TX.append(arqfile); + MailSaveFileName = szHomedir; + MailSaveFileName += '/'; + MailSaveFileName.append(MailSentFolder); + MailSaveFileName += '/'; + p = sendfilename.find_last_of('/'); + if (p != string::npos) p++; + MailSaveFileName.append(sendfilename.substr(p)); + TX.append(sendfilename.substr(p)); + TX.append("\n"); + TX.append(arqemail); + while (textfile.get(cin)) +// only allow ASCII printable characters + if ((cin >= ' ' && cin <= '~') || + (cin == 0x09 || (cin == 0x0a) || cin == 0x0d) ) + textin += cin; + textfile.close(); + txtsize = textin.length(); + arqPayloadSize = txtsize; + blocksSent = 0; + snprintf(sizemsg, sizeof(sizemsg), "ARQ:SIZE::%" PRIuSZ "\n", txtsize); + TX.append(sizemsg); + TX.append(arqstart); + TX.append(textin); + TX.append(arqend); + traffic = true; + statusmsg = "Sending email: "; + statusmsg.append(sendfilename.substr(p)); + txtStatus->value(statusmsg.c_str()); + SendingEmail = true; + sendingfile = true; + cbClearText(); + return; + } + + traffic = false; + sendingfile = false; + SendingEmail = false; +} + + +void sendAsciiFile() +{ + if (arqstate < CONNECTED) { + fl_alert2("Not connected"); + return; + } + string readfromname = szHomedir; + readfromname += '/'; + readfromname.append(OutFolder); + readfromname += '/'; + readfromname.append(rxfname); + const char *p = FSEL::select("ARQ text file", "*.txt\t*", readfromname.c_str()); + char cin; + size_t txtsize; + string textin = ""; + char sizemsg[40]; + if (p) { + ifstream textfile; + textfile.open(p); + if (textfile) { + TX.erase(); + TX.append(arqfile); + p = fl_filename_name(p); + TX.append(p); + TX.append("\n"); + TX.append(arqascii); + while (textfile.get(cin)) + textin += cin; + textfile.close(); + if ( textin.find_first_not_of(AsciiChars) != string::npos) { + fl_alert2("File contains non-ASCII bytes and must be sent as binary."); + return; + } + txtsize = textin.length(); + arqPayloadSize = txtsize; + blocksSent = 0; + snprintf(sizemsg, sizeof(sizemsg), "ARQ:SIZE::%" PRIuSZ "\n", txtsize); + TX.append(sizemsg); + TX.append(arqstart); + TX.append(textin); + TX.append(arqend); + traffic = true; + sendingfile = true; + statusmsg = "Sending ASCII file: "; + statusmsg.append(p); + txtStatus->value(statusmsg.c_str()); + cbClearText(); + return; + } + } + traffic = false; + sendingfile = false; +} + +void sendImageFile() +{ + if (arqstate < CONNECTED) { + fl_alert2("Not connected"); + return; + } + const char *p = FSEL::select("ARQ image file", "*.{png,jpg,bmp}\t*", ""); + char cin; + size_t txtsize, b64size; + string textin = ""; + string b64text; + base64 b64(true); + char sizemsg[40]; + if (p) { + ifstream textfile; + textfile.open(p, ios::binary); + if (textfile) { + TX.erase(); + TX.append(arqfile); + p = fl_filename_name(p); + TX.append(p); + TX.append("\n"); + TX.append(arqbase64); + while (textfile.get(cin)) + textin += cin; + textfile.close(); + txtsize = textin.length(); + b64text = b64.encode(textin); + b64size = b64text.length(); + snprintf(sizemsg, sizeof(sizemsg), "ARQ:SIZE::%" PRIuSZ "\n", b64size); + arqPayloadSize = b64size; + blocksSent = 0; + TX.append(sizemsg); + TX.append(arqstart); + TX.append(b64text); + TX.append(arqend); + traffic = true; + sendingfile = true; + statusmsg = "Sending image: "; + statusmsg.append(p); + txtStatus->value(statusmsg.c_str()); + cbClearText(); + return; + } + } + traffic = false; + sendingfile = false; +} + +void sendBinaryFile() +{ + if (arqstate < CONNECTED) { + fl_alert2("Not connected"); + return; + } + const char *p = FSEL::select("ARQ file", "*", ""); + char cin; + size_t txtsize, b64size; + string textin = ""; + string b64text; + base64 b64(true); + char sizemsg[40]; + if (p) { + ifstream textfile; + textfile.open(p, ios::binary); + if (textfile) { + TX.erase(); + TX.append(arqfile); + p = fl_filename_name(p); + TX.append(p); + TX.append("\n"); + TX.append(arqbase64); + while (textfile.get(cin)) + textin += cin; + textfile.close(); + txtsize = textin.length(); + b64text = b64.encode(textin); + b64size = b64text.length(); + snprintf(sizemsg, sizeof(sizemsg), "ARQ:SIZE::%" PRIuSZ "\n", b64size); + arqPayloadSize = b64size; + blocksSent = 0; + TX.append(sizemsg); + TX.append(arqstart); + TX.append(b64text); + TX.append(arqend); + traffic = true; + sendingfile = true; + statusmsg = "Sending binary: "; + statusmsg.append(p); + txtStatus->value(statusmsg.c_str()); + cbClearText(); + return; + } + } + traffic = false; + sendingfile = false; +} + +char statemsg[80]; + +void dispState() +{ + int currstate = digi_arq->state(); + static char xfrmsg[80]; + static char szPercent[10]; + + arqstate = currstate & 0x7F; + + if (arqstate == DOWN || arqstate == TIMEDOUT) { + if (btnCONNECT->active()) + btnCONNECT->label("Connect"); + if (!autobeacon) + btnBEACON->activate(); + mnuSend->deactivate(); + mnu->redraw(); + } + else if (arqstate == CONNECTED || arqstate == WAITING) { + if (btnCONNECT->active()) + btnCONNECT->label("Disconnect"); + if (!autobeacon) + btnBEACON->deactivate(); + mnuSend->activate(); + mnu->redraw(); + } + if (rxARQfile || sendingfile) { + if (btnCONNECT->active()) + btnCONNECT->label("Abort"); + } + if (btnCONNECT->active()) + btnCONNECT->redraw_label(); + + if (currstate <= 0x7F) // receiving + switch (currstate) { + case CONNECTING : + snprintf(statemsg, sizeof(statemsg), "CONNECTING: %d", digi_arq->getTimeLeft()); + txtState->value(statemsg); + txtState->redraw(); + autobeacon = false; + break; + case WAITFORACK : + snprintf(statemsg, sizeof(statemsg), "CONNECTING: %d", digi_arq->getTimeLeft()); + txtState->value(statemsg); + txtState->redraw(); + autobeacon = false; + break; + case ABORT: + case ABORTING : + txtState->value("ABORTING XFR"); + txtState->redraw(); + autobeacon = false; + break; + case WAITING : + case CONNECTED : + char szState[80]; + snprintf(szState, sizeof(szState),"CONNECTED - Quality = %4.2f", + digi_arq->quality()); + indCONNECT->color(FL_GREEN); + indCONNECT->redraw(); + txtState->value(szState); + txtURCALL->value( digi_arq->urCall().c_str() ); + autobeacon = false; + break; + case TIMEDOUT : + indCONNECT->color(FL_WHITE); + indCONNECT->redraw(); + txtState->value("TIMED OUT"); + txtStatus->value(""); + autobeacon = false; + beaconrcvd = false; + break; + case DISCONNECT: + case DISCONNECTING: + txtState->value("DISCONNECTING"); + break; + case DOWN : + default : + indCONNECT->color(FL_WHITE); + indCONNECT->redraw(); + txtState->value("NOT CONNECTED"); + txtStatus->value(""); + } + + if (sendingfile == true) { + if (digi_arq->transferComplete()) { + time(&EndTime_t); + TransferTime = difftime(EndTime_t,StartTime_t); + snprintf(xfrmsg, sizeof(xfrmsg), "Transfer Completed in %4.0f sec's", TransferTime); + txtStatus->value(xfrmsg); + blocksSent = 0; + prgStatus->value(0.0); + prgStatus->label(""); + prgStatus->redraw(); + prgStatus->redraw_label(); + sendingfile = false; + } + else { + prgStatus->value( digi_arq->percentSent()); + snprintf(szPercent, sizeof(szPercent), "%3.0f %%", 100.0 * digi_arq->percentSent()); + prgStatus->label(szPercent); + prgStatus->redraw(); + prgStatus->redraw_label(); + } + } + if (SendingEmail == true) { + if (digi_arq->transferComplete()) { + time(&EndTime_t); + TransferTime = difftime(EndTime_t,StartTime_t); + snprintf(xfrmsg, sizeof(xfrmsg), "Transfer Completed in %4.0f sec's", TransferTime); + txtStatus->value(xfrmsg); + moveEmailFile(); + blocksSent = 0; + prgStatus->value(0.0); + prgStatus->label(""); + prgStatus->redraw(); + prgStatus->redraw_label(); + SendingEmail = false; + } + else { + prgStatus->value( digi_arq->percentSent()); + snprintf(szPercent, sizeof(szPercent), "%3.0f %%", 100.0 * digi_arq->percentSent()); + prgStatus->label(szPercent); + prgStatus->redraw(); + prgStatus->redraw_label(); + } + } +} + +void mainloop(void *) +{ + + if (traffic) { + digi_arq->sendText(TX); + traffic = false; + time(&StartTime_t); + } + dispState(); + if (rxTextReady) { + if (haveemail) + saveEmailFile(); + else + saveRxFile(); + } + Fl::repeat_timeout(0.1, mainloop); +} + +void changeMyCall(const char *nucall) +{ + int currstate = digi_arq->state(); + if (currstate != DOWN) + return; + + MyCall = nucall; + for (size_t i = 0; i < MyCall.length(); i++) + MyCall[i] = toupper(MyCall[i]); + + txtMyCall->value(MyCall.c_str()); + digi_arq->myCall(MyCall.c_str()); + + string title = "flarq "; + title.append(VERSION); + title.append(" - "); + title.append(MyCall); + arqwin->label(title.c_str()); + +} + +void changeBeaconText(const char *txt) +{ + beacontext = txt; +} + +void TALKprint(string s) +{ + string style; + style.append(s.length(), 'A'); + stylebufRX->append(style.c_str()); + txtRX->insert(s.c_str()); + txtRX->show_insert_position(); + txtRX->redraw(); +} + +void clear_STATUS(void* arg) +{ + txtStatus2->value(""); +} + + +void STATUSprint(string s, double disptime) +{ + txtStatus2->value(s.c_str()); + if (disptime > 0.0) { + Fl::remove_timeout( clear_STATUS ); + Fl::add_timeout( disptime, clear_STATUS ); + } +} + +void cbSendTalk() +{ + string tosend; + string style; + tosend = txtTX->value(); + if (tosend.empty()) return; + tosend += '\n'; + digi_arq->sendPlainText(tosend); + txtTX->value(""); + style.append(tosend.length(), 'B'); + stylebufRX->append(style.c_str()); + txtRX->insert(tosend.c_str()); + txtRX->show_insert_position(); + txtRX->redraw(); +} + +void arqlog(string nom,string s) +{ + static char szGMT[80]; + tm *now; + time_t tm; + string strdebug; + + time(&tm); + now = localtime( &tm ); + strftime(szGMT, sizeof(szGMT), "[%X] ", now); + + for (unsigned int i = 0; i < s.length(); i++) + if (s[i] < 32) + strdebug += ASCII[(int)s[i]]; + else + strdebug += s[i]; + ofstream logfile(Logfile.c_str(), ios::app); + if (logfile) + logfile << nom << szGMT << strdebug << endl; +} + +void DEBUGrxprint(string s) +{ + string style; + string text = noCR(s); + style.append(text.length(), 'C'); + stylebufRX->append(style.c_str()); + txtRX->insert(text.c_str()); + txtRX->show_insert_position(); + txtRX->redraw(); + arqlog("",s); +} + +void DEBUGtxprint(string s) +{ + string style; + string text = noCR(s); + style.append(text.length(), 'D'); + stylebufRX->append(style.c_str()); + txtRX->insert(text.c_str()); + txtRX->show_insert_position(); + txtRX->redraw(); + arqlog("",s); +} + +void TXecho(string s) +{ + string style; + blocksSent += s.length(); + string text = noCR(s); + style.append(text.length(), 'B'); + stylebufARQ->append(style.c_str()); + txtARQ->insert(text.c_str()); + txtARQ->show_insert_position(); + txtARQ->redraw(); +} + + +void style_unfinished_cb(int, void*) { +} + +void cbClearTalk() +{ + txtbuffRX->text(""); + stylebufRX->text(""); +} + +void cb_arqwin(Fl_Widget *, void*) +{ + arqCLOSE(); +} + +int main (int argc, char *argv[] ) +{ + sscanf(VERSION, "%f", &version); + + set_unexpected(handle_unexpected); + set_terminate(diediedie); + setup_signal_handlers(); + +#ifdef __WOE32__ + // designate the arq home directory in Windows + // create if it does not exist + strcpy(szHomedir, str_homedir.c_str()); + ifstream test(str_homedir.c_str()); + if (!test) + mkdir(str_homedir.c_str(), 0777); + test.close(); +#else + fl_filename_expand(szHomedir, 119, "$HOME"); +#endif + Logfile = szHomedir; + Logfile.append("/").append(str_arqlog); + + set_platform_ui(); + + generate_option_help(); + generate_version_text(); + + int arg_idx; + if (Fl::args(argc, argv, arg_idx, parse_args) != argc) { + cerr << PACKAGE_NAME << ": bad option `" << argv[arg_idx] + << "'\nTry `" << PACKAGE_NAME + << " --help' for more information.\n"; + exit(EXIT_FAILURE); + } + + createAsciiChars(); // allowable ASCII text chars for ".txt" type of files + + FSEL::create(); + arqwin = arq_dialog(); + arqwin->callback(cb_arqwin); + arqwin->xclass(PACKAGE_TARNAME); + + // FL_NORMAL_SIZE may have changed; update the menu items + for (int i = 0; i < menu_mnu->size() - 1; i++) + if (menu_mnu[i].text) + menu_mnu[i].labelsize(FL_NORMAL_SIZE); + + + txtbuffRX = new Fl_Text_Buffer(); + txtRX->buffer(txtbuffRX); + txtRX->wrap_mode(1,80); + stylebufRX = new Fl_Text_Buffer(); + txtRX->highlight_data(stylebufRX, styletable, + sizeof(styletable) / sizeof(styletable[0]), + 'A', style_unfinished_cb, 0); + + txtbuffARQ = new Fl_Text_Buffer(); + txtARQ->buffer(txtbuffARQ); + txtARQ->wrap_mode(1,80); + stylebufARQ = new Fl_Text_Buffer(); + txtARQ->highlight_data(stylebufARQ, styletable, + sizeof(styletable) / sizeof(styletable[0]), + 'A', style_unfinished_cb, 0); + + digi_arq = new arq(); + + try { + tcpip = new Socket(Address(arq_address.c_str(), arq_port.c_str())); + tcpip->set_timeout(0.01); + tcpip->connect(); + } + catch (const SocketException& e) { + string errmsg; + errmsg.append("Could not connect to modem program.\nPlease start "); + if (ioMPSK) + errmsg.append("MultiPSK"); + else + errmsg.append("fldigi"); + errmsg.append(" before flarq."); + fl_alert2(errmsg.c_str()); + exit(EXIT_FAILURE); + } + + if (ioMPSK) + Fl::add_timeout(0.1, MPSK_Socket_rcv_loop); + else + Fl::add_timeout(0.1, Socket_rcv_loop); + +// the following sequence of assigning callback functions is mandatory +// for the arq class to function + if (ioMPSK) + digi_arq->setSendFunc (MPSK_client_transmit); + else + digi_arq->setSendFunc (client_transmit); + digi_arq->setGetCFunc (client_receive); + digi_arq->setAbortedTransfer(abortedTransfer); + digi_arq->setDisconnected(restart); + digi_arq->setrxUrCall (rxBeaconCallsign); + + digi_arq->setPrintRX (payloadText); + digi_arq->setPrintTX (TXecho); + digi_arq->setPrintTALK (TALKprint); + digi_arq->setPrintSTATUS (STATUSprint); + + if (SHOWDEBUG) { + digi_arq->setPrintRX_DEBUG (DEBUGrxprint); + digi_arq->setPrintTX_DEBUG (DEBUGtxprint); + } + + digi_arq->start_arq(); + + readConfig(); + + string title = "flarq "; + title.append(VERSION); + title.append(" - "); + title.append(MyCall); + arqwin->label(title.c_str()); + + arqwin->resize(mainX, mainY, mainW, mainH); + + txtBeaconing->value("Beacon Off"); + + Fl::add_timeout(0.1, mainloop); + +#ifdef __WOE32__ +# ifndef IDI_ICON +# define IDI_ICON 101 +# endif + arqwin->icon((char*)LoadIcon(fl_display, MAKEINTRESOURCE(IDI_ICON))); +#elif !defined(__APPLE__) + make_pixmap(&flarq_icon_pixmap, flarq_icon); + arqwin->icon((char *)flarq_icon_pixmap); +#endif + + arqwin->show(argc, argv); + return Fl::run(); +} diff --git a/src/flarq-src/flarqenv.cxx b/src/flarq-src/flarqenv.cxx new file mode 100644 index 00000000..15cb2356 --- /dev/null +++ b/src/flarq-src/flarqenv.cxx @@ -0,0 +1,301 @@ +#include + +#include +#include +#include + +#include +#include +#include + +#ifdef __MINGW32__ +# include "compat.h" +#endif + +#if HAVE_SYS_UTSNAME_H +# include +#endif + +#include +#include + +#include + +#include "stacktrace.h" +#include "flarq.h" + +using namespace std; + +string option_help, version_text, build_text; +extern string arq_address, arq_port; +extern bool ioMPSK; +extern bool SHOWDEBUG; + +void generate_option_help(void) +{ + ostringstream help; + help << "Usage:\n" + << " " << PACKAGE_NAME << " [option...]\n\n"; + + help << PACKAGE_NAME << " options:\n\n" + << " --arq-protocol TYPE\n" + << " Set the ARQ protocol\n" + << " May be either ``fldigi'' or ``multipsk''\n" + << " The default is: " << (ioMPSK ? "multipsk" : "fldigi") << "\n\n" + + << " --arq-server-address HOSTNAME\n" + << " Set the ARQ TCP server address\n" + << " The default is: " << arq_address << "\n\n" + + << " --arq-server-port PORT\n" + << " Set the ARQ TCP server port\n" + << " The default is: " << arq_port << "\n\n" + + << " --debug\n" + << " Enable debugging messages\n\n" + + << " --version\n" + << " Print version information\n\n" + + << " --build-info\n" + << " Print build information\n\n" + + << " --help\n" + << " Print this option help\n\n"; + +// Fl::help looks ugly so we'll write our own + + help << "Standard FLTK options:\n\n" + + << " -bg COLOR, -background COLOR\n" + << " Set the background color\n" + + << " -bg2 COLOR, -background2 COLOR\n" + << " Set the secondary (text) background color\n\n" + + << " -di DISPLAY, -display DISPLAY\n" + << " Set the X display to use DISPLAY,\n" + << " format is ``host:n.n''\n\n" + + << " -dn, -dnd or -nodn, -nodnd\n" + << " Enable or disable drag and drop copy and paste in text fields\n\n" + + << " -fg COLOR, -foreground COLOR\n" + << " Set the foreground color\n\n" + + << " -g GEOMETRY, -geometry GEOMETRY\n" + << " Set the initial window size and position\n" + << " GEOMETRY format is ``WxH+X+Y''\n" + << " ** " << PACKAGE_NAME << " may override this setting **\n\n" + + << " -i, -iconic\n" + << " Start " << PACKAGE_NAME << " in iconified state\n\n" + + << " -k, -kbd or -nok, -nokbd\n" + << " Enable or disable visible keyboard focus in non-text widgets\n\n" + + << " -na CLASSNAME, -name CLASSNAME\n" + << " Set the window class to CLASSNAME\n\n" + + << " -ti WINDOWTITLE, -title WINDOWTITLE\n" + << " Set the window title\n\n"; + + help << "Additional UI options:\n\n" + + << " --font FONT[:SIZE]\n" + << " Set the widget font and (optionally) size\n" + << " The default is: " << Fl::get_font(FL_HELVETICA) + << ':' << FL_NORMAL_SIZE << "\n\n"; + + option_help = help.str(); +} + +int parse_args(int argc, char** argv, int& idx) +{ + // Only handle long options + if ( !(strlen(argv[idx]) >= 2 && strncmp(argv[idx], "--", 2) == 0) ) + return 0; + + enum { OPT_ZERO, +#ifndef __WOE32__ + OPT_RX_IPC_KEY, OPT_TX_IPC_KEY, +#endif + OPT_ARQ_PROTOCOL, OPT_ARQ_ADDRESS, OPT_ARQ_PORT, + + OPT_FONT, + + OPT_DEBUG, OPT_DEPRECATED, OPT_HELP, OPT_VERSION, OPT_BUILD_INFO + }; + + const char shortopts[] = "+"; + struct option longopts[] = { +#ifndef __WOE32__ + { "rx-ipc-key", 1, 0, OPT_RX_IPC_KEY }, + { "tx-ipc-key", 1, 0, OPT_TX_IPC_KEY }, +#endif + { "arq-protocol", 1, 0, OPT_ARQ_PROTOCOL }, + { "arq-server-address", 1, 0, OPT_ARQ_ADDRESS }, + { "arq-server-port", 1, 0, OPT_ARQ_PORT }, + + { "font", 1, 0, OPT_FONT }, + + { "debug", 0, 0, OPT_DEBUG }, + + { "help", 0, 0, OPT_HELP }, + { "version", 0, 0, OPT_VERSION }, + { "build-info", 0, 0, OPT_BUILD_INFO }, + { 0 } + }; + + int longindex; + optind = idx; + int c = getopt_long(argc, argv, shortopts, longopts, &longindex); + + switch (c) { + case -1: + return 0; + case 0: + // handle options with non-0 flag here + return 0; + + case OPT_ARQ_PROTOCOL: + if (!strcmp(optarg, "fldigi")) + ioMPSK = false; + else if (!strcmp(optarg, "multipsk")) + ioMPSK = true; + else { + cerr << "E: unknown protocol type\n"; + exit(EXIT_FAILURE); + } + break; + case OPT_ARQ_ADDRESS: + arq_address = optarg; + break; + case OPT_ARQ_PORT: + arq_port = optarg; + break; + + case OPT_FONT: { + char *p; + if ((p = strchr(optarg, ':'))) { + *p = '\0'; + FL_NORMAL_SIZE = strtol(p + 1, 0, 10); + } + + Fl::set_font(FL_HELVETICA, optarg); + break; + } + + case OPT_DEBUG: + SHOWDEBUG = true; + break; + + case OPT_DEPRECATED: + cerr << "W: the --" << longopts[longindex].name + << " option has been deprecated and will be removed in a future version\n"; + break; + + case OPT_HELP: + cout << option_help; + exit(EXIT_SUCCESS); + + case OPT_VERSION: + cout << version_text; + exit(EXIT_SUCCESS); + + case OPT_BUILD_INFO: + cout << build_text; + exit(EXIT_SUCCESS); + + case '?': default: + cerr << "Try `" << PACKAGE_NAME << " --help' for more information.\n"; + exit(EXIT_FAILURE); + + } + + // Increment idx by the number of args we used and return that number. + // We must check whether the option argument is in the same argv element + // as the option name itself, i.e., --opt=arg. + c = longopts[longindex].has_arg ? 2 : 1; + if (c == 2) { + string arg = argv[idx]; + string::size_type p; + if ((p = arg.rfind(optarg)) != string::npos && arg[p-1] == '=') + c = 1; + } + idx += c; + return c; +} + +void set_platform_ui(void) +{ +#if defined(__APPLE__) + FL_NORMAL_SIZE = 12; +#elif defined(__WOE32__) + Fl::set_font(FL_HELVETICA, "Tahoma"); + FL_NORMAL_SIZE = 11; +#else + FL_NORMAL_SIZE = 12; +#endif +} + +void generate_version_text(void) +{ + version_text.assign(PACKAGE_STRING "\nCopyright (C) 2008, 2009 " PACKAGE_AUTHORS ".\n"); + version_text.append("License GPLv2+: GNU GPL version 2 or later " + "\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n"); + + ostringstream s; + s << "Build information:\n"; + s << " built : " << BUILD_DATE << " by " << BUILD_USER + << '@' << BUILD_HOST << " on " << BUILD_BUILD_PLATFORM + << " for " << BUILD_TARGET_PLATFORM << "\n\n" + << " configure flags: " << BUILD_CONFIGURE_ARGS << "\n\n" + << " compiler : " << BUILD_COMPILER << "\n\n" + << " compiler flags : " << FLARQ_BUILD_CXXFLAGS << "\n\n" + << " linker flags : " << FLARQ_BUILD_LDFLAGS << "\n\n" + + << " libraries : " "FLTK " FLTK_BUILD_VERSION "\n"; + + s << "\nRuntime information:\n"; + struct utsname u; + if (uname(&u) != -1) { + s << " system : " << u.sysname << ' ' << u.nodename + << ' ' << u.release << ' ' << u.version << ' ' << u.machine << "\n\n"; + } + + build_text = s.str(); +} + +void setup_signal_handlers(void) +{ +#ifndef __WOE32__ + struct sigaction action; + memset(&action, 0, sizeof(struct sigaction)); + + // no child stopped notifications, no zombies + action.sa_handler = SIG_DFL; + action.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT; + sigaction(SIGCHLD, &action, NULL); + action.sa_flags = 0; + + action.sa_handler = handle_signal; + sigaction(SIGSEGV, &action, NULL); + sigaction(SIGILL, &action, NULL); + sigaction(SIGABRT, &action, NULL); + sigaction(SIGUSR2, &action, NULL); + + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); + + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, SIGUSR2); + pthread_sigmask(SIG_BLOCK, &action.sa_mask, NULL); +#else + signal(SIGSEGV, handle_signal); + signal(SIGILL, handle_signal); + signal(SIGABRT, handle_signal); +#endif +} diff --git a/src/flarq-src/flarqrc.rc b/src/flarq-src/flarqrc.rc new file mode 100644 index 00000000..c1902bad --- /dev/null +++ b/src/flarq-src/flarqrc.rc @@ -0,0 +1,5 @@ +#include // include for version info constants + +#define IDI_ICON 101 + +IDI_ICON ICON DISCARDABLE "flarq.ico" diff --git a/src/flarq-src/include/arq.h b/src/flarq-src/include/arq.h new file mode 100644 index 00000000..793d0067 --- /dev/null +++ b/src/flarq-src/include/arq.h @@ -0,0 +1,422 @@ +#ifndef arq_H +#define arq_H + +// arq module arq.h +// Copyright (c) 2007, Dave Freese, W1HKJ +// +// +// arq.cxx / arq.h is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// arq.pm 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 tUr program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// link layer spec for fldigi_arq +// +// generic Frame format: +// dcl[info])12EF +// | ||| | | | +// | ||| | | +--ASCII or (0x04) character +// | ||| | +-------checksum (4xAlphaNum) +// | ||| +-------------Payload (1 ... 2^N chars, N 4, 5, 6, 7 8) +// | ||+---------------Block type +// | |+----------------Stream id +// | +-----------------Protocol version number +// +---------------------ASCII (0x01) character +// BLOCKSIZE = 2^n +// + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +#define DEBUG + +#define arq_Version "arq 0.1" +//===================================================================== +// following Block Types are defined in K9PS ARQ Protocol specification +#define IDENT 'i' +#define CONREQ 'c' +#define CONACK 'k' +#define REFUSED 'r' +#define DISREQ 'd' +#define STATUS 's' +#define POLL 'p' +#define FMTFAIL 'f' +// following Block Types are extensions to the K9PS specification +#define _ABORT 'a' +#define _ACKABORT 'o' +#define _DISACK 'b' +#define _UNPROTO 'u' +#define _TALK 't' +//===================================================================== +#define SOH 0X01 +#define STX 0X02 +#define ACK 0X06 +#define SUB 0X1A +#define EOT 0X04 +//===================================================================== +//ARQ defaults +#define MAXHEADERS 8 // Max. number of missing blocks +#define MAXCOUNT 64 // DO NOT CHANGE THIS CONSTANT +#define EXPONENT 7 // Bufferlength = 2 ^ EXPONENT = 128 +//===================================================================== +//link timing defaults +#define RETRIES 5 +#define RETRYTIME 10000 // # milliseconds between retries +#define TXDELAY 500 // # milliseconds from xmt to rcv +#define TIMEOUT 60000 // # milliseconds before TIMED OUT +#define ARQLOOPTIME 100 // # msec for loop timing +//===================================================================== +//link states +#define DOWN 0 +#define TIMEDOUT 1 +#define ABORT 3 +#define CONNECTING 4 +#define CONNECTED 5 +#define WAITING 6 +#define WAITFORACK 7 +#define DISCONNECT 8 +#define DISCONNECTING 9 +#define ABORTING 10 + +#define SENDING 0x80; + +//===================================================================== + +extern char *ARQASCII[]; + +// crc 16 cycle redundancy check sum for data block integrity + +class Ccrc16 { +private: + unsigned int crcval; + char ss[5]; +public: + Ccrc16() { crcval = 0xFFFF; } + ~Ccrc16() {}; + void reset() { crcval = 0xFFFF;} + unsigned int val() {return crcval;} + string sval() { + snprintf(ss, sizeof(ss), "%04X", crcval); + return ss; + } + void update(char c) { + crcval ^= c; + for (int i = 0; i < 8; ++i) { + if (crcval & 1) + crcval = (crcval >> 1) ^ 0xA001; + else + crcval = (crcval >> 1); + } + } + unsigned int crc16(char c) { + update(c); + return crcval; + } + unsigned int crc16(string s) { + reset(); + for (size_t i = 0; i < s.length(); i++) + update(s[i]); + return crcval; + } + string scrc16(string s) { + crc16(s); + return sval(); + } +}; + +// text block; block # and string of text +class cTxtBlk { +private: + int number; + string txt; +public: + cTxtBlk() {number = -1; txt = "";} + cTxtBlk(int n, string text) { number = n; txt = text; } + ~cTxtBlk() {} + void nbr(int n) { number = n;} + int nbr() { return number; } + string text() { return txt; } + void text(string t) { txt = t;} + bool operator <(const cTxtBlk &b)const { return number < b.number; } + bool operator ==(const cTxtBlk b)const { return number == b.number; } +}; + + +class arq { + +private: + bool arqstop; + + string MyCall; + string UrCall; + + string Header; + string Frame; + string Payload; + string rcvPayload; + + string logfile; + + char MyStreamID; + char UrStreamID; + + char MyBlockLengthChar; + char UrBlockLengthChar; + char BlockNumberChar; + char fID; + int blknbr; + +// queues // + string TxTextQueue; // Text out to mail engine + string TxPlainTextQueue; // plain text transmit queu + string RxTextQueue; // Text in from mail engine + string RxFrameQueue; + char lastRxChar; + bool TXflag; + + int Sessionnumber; + int Bufferlength; + int maxheaders; + int exponent; + +// status variables + int payloadlength; // Average length of payload received + long totalRx; // total number of frames received + long totalTx; // total number of frames transmitted + long nbrbadRx; // number with crc errors + long nbrbadTx; // total number of repeats required +// int max_idle; // Dynamic timing slot initial value + int SessionNumber; + bool PollOK; // used for status handshake + bool wrappedFlag; // set true if missing blocks bit count + // has wrapped around + long retrytime; + long RetryTime; + long retries; + long Retries; + long timeout; + long Timeout; + long tx2txdelay; + long TxDelay; + long loopcount; + + long baseRetryTime; + long baseTimeout; + long baseRetries; + + bool immediate; + bool primary; + + Ccrc16 framecrc; + +// My status + int Firstsent; // First Header I sent last turn + int LastHeader; // Last Header I sent last turn + int Lastqueued; // Last Header in static send queue + + int EndHeader; // Last I received o.k. + int GoodHeader; // Last Header received consecutively + int blkcount; + int Blocks2Send; // number of blocks at beginning of Tx + + vector MyMissing; // missing Rx blocks + string MissingRxBlocks; + vector RxPending; // RxPending Rx blocks (not consecutive) + + list TxBlocks; // fifo of transmit buffers + list TxMissing; // fifo of sent; RxPending Status report + list TxPending; // fifo of transmitted buffers pending print + +// Ur status + int UrGoodHeader; // Other station's Good Header + int UrLastHeader; // Other station's Header last sent + int UrEndHeader; // Other station's last received Header + vector UrMissing; // Other station's missing Headers + + int LinkState; // status of ARQ link + int Sending; + + bool bABORT; + +// Link quality for sending *** used for testing only !! *** +// double sendquality; + + + void reset(); + void resetTx(); + void resetRx(); + int rtry(); + + void setBufferlength(); + + void checkblocks(); + string upcase(string s); + void newblocknumber(); + void newHeader(); + void IdHeader(); + void UnkHeader(); + + void connectFrame(); + void disackFrame(); + void ackFrame(); + void ttyconnectFrame(); + void ttyackFrame(); + void pollFrame(); + void identFrame(); + void pingFrame(); + void statFrame(); + void disconnectFrame(); + void abortFrame(); + void ackAbortFrame(); + void beaconFrame(string txt); + void textFrame(cTxtBlk block); + void talkFrame(string txt); + + void addToTxQue(string s); + + void sendblocks(); + void transmitdata(); + + string frame() {return Frame;} + + bool isUrcall(); + void parseIDENT(); + void parseCONREQ(); + void parseCONACK(); + void parseREFUSED(); + void parseDISREQ(); + void parseDISACK(); + void parseABORT(); + void parseACKABORT(); + void parseUNPROTO(); + void parseSTATUS(); + void parsePOLL(); + void parseDATA(); + void parseTALK(); + + int parseFrame(string txt); + +// external functions called by arq class + void (*sendfnc)(const string& s); + bool (*getc1)(char &); + void (*rcvfnc)(); + void (*printRX)(string s); + void (*printTX)(string s); + void (*printRX_DEBUG)(string s); + void (*printTX_DEBUG)(string s); + void (*printTALK)(string s); + void (*abortfnc)(); + void (*disconnectfnc)(); + void (*rxUrCall)(string s); + void (*qualityfnc)(string s); + void (*printSTATUS)(string s, double disptime); + +public: + arq(); + ~arq() {}; + + friend void arqloop(void *me); + void start_arq(); + + string checksum(string &s); + + void myCall(string s) { MyCall = upcase(s);} + string myCall() { return MyCall;} + + void urCall(string s) { UrCall = s;} + string urCall() { return UrCall;} + + void newsession(); + + void setSendFunc( void (*f)(const string& s)) { sendfnc = f;} + void setGetCFunc( bool (*f)(char &)) { getc1 = f;} + void setRcvFunc( void (*f)()) { rcvfnc = f;} + + void setPrintRX( void (*f)(string s)) { printRX = f;} + void setPrintTX( void (*f)(string s)) { printTX = f;} + void setPrintTALK (void (*f)(string s)) {printTALK = f;} + void setPrintRX_DEBUG (void (*f)(string s)){printRX_DEBUG = f;} + void setPrintTX_DEBUG (void (*f)(string s)) {printTX_DEBUG = f;} + void setPrintSTATUS (void (*f)(string s, double disptime)) { printSTATUS = f;} + + void setMaxHeaders( int mh ) { maxheaders = mh; } + void setExponent( int exp ) { exponent = exp; setBufferlength(); } + int getExponent() { return (int) exponent;} + void setWaitTime( int rtime ) { RetryTime = rtime; baseRetryTime = rtime; } + int getWaitTime() { return (int) RetryTime; } + void setRetries ( int rtries ) { + retries = Retries = baseRetries = rtries; } + int getRetries() { return (int) Retries; } + void setTimeout ( int tout ) { Timeout = tout; baseTimeout = tout; } + int getTimeout() { return (int) Timeout; } + int getTimeLeft() { return (int) timeout * ARQLOOPTIME / 1000; } + void setTxDelay ( int r2t ) { TxDelay = r2t; } + int getTxDelay() { return (int) TxDelay; } + int getRetryCount() { return (int)(Retries - retries + 1); } + + void setrxUrCall( void (*f)(string s)) { rxUrCall = f;} + void setQualityValue( void (*f)(string s)) { qualityfnc = f;} + void setAbortedTransfer( void (*f)()) { abortfnc = f;}; + void setDisconnected( void (*f)()) { disconnectfnc = f;}; + + void rcvChar( char c ); + + void connect(string callsign);//, int blocksize = 6, int retries = 4); + + void sendblocks( string txt ); + + void sendBeacon (string txt); + void sendPlainText( string txt ); + + string getText() { return RxTextQueue;} + void sendText(string txt); + + bool connected() { return (LinkState == CONNECTED); } + void disconnect(); + void abort(); + + int state() { return (LinkState + Sending);} + + int TXblocks() { return totalTx;} + int TXbad() { return nbrbadTx;} + int RXblocks() { return totalRx;} + int RXbad() { return nbrbadRx;} + + double quality() { + if (totalTx == 0) return 1.0; + return ( 1.0 * (totalTx - nbrbadTx) / totalTx ); + } + + float percentSent() { + if (Blocks2Send == 0) return 0.0; + if ((TxBlocks.empty() && TxMissing.empty())) return 1.0; + return (1.0 * (Blocks2Send - TxBlocks.size() - TxMissing.size()) / Blocks2Send); + } + + bool transferComplete() { + if (TxMissing.empty() == false) return false; + if (TxBlocks.empty() == false) return false; + return true; + } +}; + +#endif + diff --git a/src/flarq-src/include/arqdialogs.h b/src/flarq-src/include/arqdialogs.h new file mode 100644 index 00000000..fb47f6be --- /dev/null +++ b/src/flarq-src/include/arqdialogs.h @@ -0,0 +1,89 @@ +// generated by Fast Light User Interface Designer (fluid) version 1.0109 + +#ifndef arqdialogs_h +#define arqdialogs_h +#include +#include "flinput2.h" +#include +#include +extern Fl_Menu_Bar *mnu; +extern void ComposeMail(); +extern void cbMenuConfig(); +extern void cbMenuAbout(); +#include +#include +extern Fl_Button *btnCONNECT; +extern Fl_Input2 *txtURCALL; +#include +extern Fl_Light_Button *btnBEACON; +extern Fl_Input2 *txtBeaconing; +#include +extern Fl_Box *indCONNECT; +extern Fl_Input2 *txtState; +#include +extern Fl_Text_Display *txtARQ; +extern Fl_Input2 *txtStatus; +extern Fl_Input2 *txtStatus2; +#include +extern Fl_Progress *prgStatus; +extern Fl_Button *btnClearText; +extern Fl_Text_Display *txtRX; +extern Fl_Input2 *txtTX; +extern Fl_Button *btnSendTalk; +Fl_Double_Window* arq_dialog(); +extern Fl_Menu_Item menu_mnu[]; +#define mnuExit (menu_mnu+1) +#define mnuSend (menu_mnu+3) +#define mnuSendEmail (menu_mnu+4) +#define mnuSendText (menu_mnu+5) +#define mnuSendImage (menu_mnu+6) +#define mnuSendBinary (menu_mnu+7) +#define mnuCompose (menu_mnu+9) +#define mnuConfig (menu_mnu+10) +#define mnuHelp (menu_mnu+11) +#define mnuHowTo (menu_mnu+12) +#define mnuAbout (menu_mnu+13) +extern Fl_Input2 *txtMyCall; +extern Fl_Input2 *txtFolder; +extern Fl_Input2 *txtOutputFolder; +extern Fl_Input2 *txtMail_IN; +extern Fl_Input2 *txtMail_OUT; +extern Fl_Input2 *txtMail_SENT; +#include +extern Fl_Check_Button *btnSylpheedMail; +#include +extern Fl_Spinner *spnExponent; +extern Fl_Spinner *spnRetries; +extern Fl_Spinner *spnWaitTime; +extern Fl_Spinner *spnTimeout; +extern Fl_Spinner *spnTxDelay; +extern Fl_Spinner *spnBcnInterval; +extern Fl_Input2 *txtBlockSize; +extern Fl_Button *btnOK; +extern Fl_Input2 *txtBEACONTXT; +Fl_Double_Window* arq_configure(); +#include "table.h" +extern Table *tblOutgoing; +extern void sendCancel(); +extern Fl_Button *send_Cancel; +#include +extern void sendOK(); +extern Fl_Return_Button *send_OK; +Fl_Double_Window* arq_SendSelect(); +extern Fl_Input2 *inpMailTo; +extern Fl_Input2 *inpMailSubj; +#include +extern Fl_Text_Editor *txtMailText; +#include +extern void cb_OpenComposeMail(); +extern Fl_Button *btnOpenComposedMail; +extern void cb_ClearComposer(); +extern Fl_Button *btnClearComposer; +extern void cb_UseTemplate(); +extern Fl_Button *btnUseTemplate; +extern void cb_CancelComposeMail(); +extern Fl_Button *btnCancelComposedMail; +extern void cb_SaveComposeMail(); +extern Fl_Button *btnSaveComposedMail; +Fl_Double_Window* arq_composer(); +#endif diff --git a/src/flarq-src/include/b64.h b/src/flarq-src/include/b64.h new file mode 100644 index 00000000..c17ad1d2 --- /dev/null +++ b/src/flarq-src/include/b64.h @@ -0,0 +1,34 @@ +//===================================================================== +// +// base64 encoding / decoding class +// +//===================================================================== + +#include +#include +#include + +#include + +using namespace std; + +typedef unsigned char byte; + +class base64 { +#define LINELEN 72 +private: + string output; + size_t iolen; + size_t iocp; + bool ateof; + byte dtable[256]; + byte etable[256]; + int linelength; + bool crlf; + void init(); +public: + base64(bool t = false) {crlf = t; init(); }; + ~base64(){}; + string encode(string in); + string decode(string in); +}; diff --git a/src/flarq-src/include/flarq.h b/src/flarq-src/include/flarq.h new file mode 100644 index 00000000..44cb250a --- /dev/null +++ b/src/flarq-src/include/flarq.h @@ -0,0 +1,57 @@ +#ifndef FLARQ_H +#define FLARQ_H + +#include + +#define SOHCOUNT 10 + +extern void arqBEACON(); +extern void arqCLOSE(); +extern void arqCONNECT(); +extern void cbMenuAbout(); +extern void cbMenuConfig(); +extern void cbSetConfig(); +extern void closeConfig(); +extern void sendCancel(); +extern void sendOK(); +extern void cb_SortByDate(); +extern void cb_SortByTo(); +extern void cb_SortBySubj(); +extern void abortTransfer(); +extern void cbAbort(); +extern void cbClearText(); +extern void testDirectory(std::string); +extern void cbSendTalk(); +extern void cbClearTalk(); +extern void help_cb(); + +extern void sendEmailFile(); +extern void sendAsciiFile(); +extern void sendImageFile(); +extern void sendBinaryFile(); +extern void changeMyCall(const char *); +extern void changeBeaconText(const char *); + +extern std::string MyCall; +extern std::string InFolder; +extern std::string OutFolder; +extern std::string MailInFolder; +extern std::string MailOutFolder; +extern std::string MailSentFolder; +extern std::string Logfile; +extern bool bSylpheedFolder; +extern std::string beacontext; +extern int exponent; +extern int txdelay; +extern int iretries; +extern long iwaittime; +extern long itimeout; +extern int bcnInterval; + +extern void cb_SaveComposeMail(); +extern void cb_CancelComposeMail(); +extern void cb_UseTemplate(); +extern void cb_OpenComposeMail(); +extern void ComposeMail(); + +#endif diff --git a/src/flarq-src/include/flarqenv.h b/src/flarq-src/include/flarqenv.h new file mode 100644 index 00000000..a181cdd8 --- /dev/null +++ b/src/flarq-src/include/flarqenv.h @@ -0,0 +1,14 @@ +#ifndef flarqenv_h_ +#define flarqenv_h_ + +#include + +extern std::string option_help, version_text, build_text; + +void generate_option_help(void); +void generate_version_text(void); +int parse_args(int argc, char** argv, int& idx); +void set_platform_ui(void); +void setup_signal_handlers(void); + +#endif // flarqenv_h_ diff --git a/src/include/pixmaps.h b/src/include/pixmaps.h index fe3b2821..1ee6a3da 100644 --- a/src/include/pixmaps.h +++ b/src/include/pixmaps.h @@ -57,6 +57,7 @@ extern const char *tx2_icon[]; extern const char *rx_icon[]; extern const char *tx_icon[]; extern const char *fldigi_icon[]; +extern const char *flarq_icon[]; extern const char *waterfall_icon[]; extern const char *dice_icon[]; extern const char *pskr_icon[]; diff --git a/src/include/pkg.h b/src/include/pkg.h new file mode 100644 index 00000000..944a6b87 --- /dev/null +++ b/src/include/pkg.h @@ -0,0 +1,24 @@ +#ifndef PKG_H_ +#define PKG_H_ + +#include + +#if BUILD_FLDIGI +# define PACKAGE_AUTHORS FLDIGI_AUTHORS +#else +# define PACKAGE_AUTHORS FLARQ_AUTHORS +# undef PACKAGE +# define PACKAGE "flarq" +# undef PACKAGE_NAME +# define PACKAGE_NAME "flarq" +# undef PACKAGE_TARNAME +# define PACKAGE_TARNAME "flarq" +# undef PACKAGE_VERSION +# define PACKAGE_VERSION FLARQ_VERSION +# undef PACKAGE_STRING +# define PACKAGE_STRING PACKAGE_TARNAME " " PACKAGE_VERSION +# undef VERSION +# define VERSION PACKAGE_VERSION +#endif + +#endif diff --git a/src/main.cxx b/src/main.cxx index d0ff6424..8d2f377b 100644 --- a/src/main.cxx +++ b/src/main.cxx @@ -803,8 +803,8 @@ void generate_version_text(void) << " for " << BUILD_TARGET_PLATFORM << "\n\n" << " configure flags: " << BUILD_CONFIGURE_ARGS << "\n\n" << " compiler : " << BUILD_COMPILER << "\n\n" - << " compiler flags : " << BUILD_CXXFLAGS << "\n\n" - << " linker flags : " << BUILD_LDFLAGS << "\n\n" + << " compiler flags : " << FLDIGI_BUILD_CXXFLAGS << "\n\n" + << " linker flags : " << FLDIGI_BUILD_LDFLAGS << "\n\n" << " libraries : " "FLTK " FLTK_BUILD_VERSION "\n" << " " "libsamplerate " << SAMPLERATE_BUILD_VERSION "\n"; diff --git a/src/misc/icons.cxx b/src/misc/icons.cxx index 575b47f1..44044f3a 100644 --- a/src/misc/icons.cxx +++ b/src/misc/icons.cxx @@ -25,6 +25,8 @@ #include #include +#include +#include #if USE_IMAGE_LABELS # include @@ -35,7 +37,6 @@ # include # include -#include "configuration.h" #endif diff --git a/src/misc/macros.cxx b/src/misc/macros.cxx index 54e84654..0faa0b84 100644 --- a/src/misc/macros.cxx +++ b/src/misc/macros.cxx @@ -525,7 +525,7 @@ void pRSID(string &s, size_t &i) #ifndef __MINGW32__ void set_env(void) { - enum { PATH, FLDIGI_RX_IPC_KEY, FLDIGI_TX_IPC_KEY, FLDIGI_VERSION, + enum { PATH, FLDIGI_RX_IPC_KEY, FLDIGI_TX_IPC_KEY, FLDIGI_VERSION_ENVVAR, FLDIGI_PID, FLDIGI_CONFIG_DIR, FLDIGI_MY_CALL, FLDIGI_MY_NAME, FLDIGI_MY_LOCATOR, diff --git a/src/misc/pixmaps.cxx b/src/misc/pixmaps.cxx index 971226f7..c9144623 100644 --- a/src/misc/pixmaps.cxx +++ b/src/misc/pixmaps.cxx @@ -6843,3 +6843,968 @@ const char *fldigi_icon[] = { ". . . . . . . . . . . . . I H . . . O 5.}+o |+t 1+X.C..+,+p.8 ).9 . . . y.0.. . . . . . . . . . ", ". . . . . 9 9 . . . . . . P 9 . . . . . . p X D.9 P O <.~.2+. . . . . . :.<.. . . . . . . . . . ", ". . . . . @ @ . . . . . . . . . . . . . . &.I . . . . . ~.T.. . . . . . #.P.. . . . . . . . . . "}; + + +/* XPM */ +const char *flarq_icon[] = { +/* columns rows colors chars-per-pixel */ +"48 35 924 2", +" c None", +". c #5B1E0E", +"+ c #7F381B", +"@ c #A7624B", +"# c #A8624E", +"$ c #652012", +"% c #90555F", +"& c #AA7A86", +"* c #D4B5BE", +"= c #5E231C", +"- c #540900", +"; c #AC5D55", +"> c #B4644F", +", c #CF7F58", +"' c #FCAD85", +") c #FBB18F", +"! c #BA7057", +"~ c #965140", +"{ c #4F1509", +"] c #3B1314", +"^ c #45151B", +"/ c #895156", +"( c #AB8687", +"_ c #D7C6C1", +": c #FFFFFD", +"< c #FFFFFE", +"[ c #A58088", +"} c #945D68", +"| c #642D34", +"1 c #AC6352", +"2 c #A45C49", +"3 c #A35B46", +"4 c #CC8C74", +"5 c #F4B8A0", +"6 c #FAC5A8", +"7 c #FFD4B3", +"8 c #FFD8B8", +"9 c #FFDCBD", +"0 c #FFCFAC", +"a c #E7A380", +"b c #A2563C", +"c c #984D37", +"d c #A2787A", +"e c #997474", +"f c #AA8B91", +"g c #D1C0C6", +"h c #CAB3BD", +"i c #FBE6F1", +"j c #F9FFFF", +"k c #F8FAFA", +"l c #FEFFFF", +"m c #F3F2EF", +"n c #E9D7D9", +"o c #AC9092", +"p c #AC8C8D", +"q c #926A6E", +"r c #9A737B", +"s c #9B747C", +"t c #9E573C", +"u c #98543D", +"v c #9A5F47", +"w c #BF8469", +"x c #E9AE90", +"y c #FFCAA8", +"z c #FFD9B6", +"A c #FFDFBA", +"B c #FDE1BA", +"C c #FDDEB8", +"D c #FEDBBB", +"E c #FBDBC3", +"F c #F8DBC5", +"G c #FFDCC3", +"H c #FFD1AF", +"I c #FBB891", +"J c #E79B74", +"K c #9A4E30", +"L c #9B5644", +"M c #7D4F54", +"N c #D0BCBE", +"O c #F5EDE7", +"P c #FCF4EE", +"Q c #FFFAFC", +"R c #FFFFFF", +"S c #C7BDC6", +"T c #C4B0BD", +"U c #F4F3F8", +"V c #FDFCFF", +"W c #FFFDFF", +"X c #F7FFFF", +"Y c #DEDCDC", +"Z c #E6E1E1", +"` c #FFFAF9", +" . c #FFF3F5", +".. c #FFF4F7", +"+. c #E2D9DA", +"@. c #C1AEB5", +"#. c #C5A3AF", +"$. c #7B5057", +"%. c #7D2F24", +"&. c #C87559", +"*. c #EA9464", +"=. c #FFA873", +"-. c #FFB886", +";. c #FFC193", +">. c #FBBD92", +",. c #FBBE92", +"'. c #F9B98A", +"). c #FAB784", +"!. c #F8AE77", +"~. c #F9AC76", +"{. c #F3A97B", +"]. c #F3BB97", +"^. c #FDD7BD", +"/. c #FEDCC3", +"(. c #FFDBB4", +"_. c #FED2A6", +":. c #FEBF94", +"<. c #E89574", +"[. c #D07355", +"}. c #C06F4F", +"|. c #C09581", +"1. c #F0F1E9", +"2. c #E8FBF4", +"3. c #EEF9F3", +"4. c #FDFDFE", +"5. c #FDF8FE", +"6. c #EFE7ED", +"7. c #A6969F", +"8. c #F2E9EF", +"9. c #F7F9F9", +"0. c #FEFDFF", +"a. c #B2A3AC", +"b. c #CBBFC7", +"c. c #FCFBFE", +"d. c #F9F6F8", +"e. c #F5F8F7", +"f. c #F6FFFF", +"g. c #69302D", +"h. c #5D0100", +"i. c #A0402C", +"j. c #CC7D59", +"k. c #BF6F4E", +"l. c #C16645", +"m. c #F6996A", +"n. c #FCA264", +"o. c #F8995F", +"p. c #F3925E", +"q. c #F29968", +"r. c #F29F71", +"s. c #E79469", +"t. c #C26640", +"u. c #CF6A43", +"v. c #FD9366", +"w. c #FF9B68", +"x. c #F99B63", +"y. c #F19F6E", +"z. c #EEAB80", +"A. c #F8C59B", +"B. c #FBD3AB", +"C. c #FCD2AA", +"D. c #FCD9B1", +"E. c #F8D1AA", +"F. c #F9C596", +"G. c #FFB371", +"H. c #FEAC6B", +"I. c #D69B78", +"J. c #EAD5D1", +"K. c #ECF6FA", +"L. c #F1FAFB", +"M. c #FFFBFF", +"N. c #FDF4FB", +"O. c #FDFAFB", +"P. c #D3CACE", +"Q. c #D8C7CE", +"R. c #F6FAF8", +"S. c #FEFCFF", +"T. c #C4B4C0", +"U. c #D3C8D3", +"V. c #FAFBFF", +"W. c #FBFBFF", +"X. c #FBFDFF", +"Y. c #F7FEFF", +"Z. c #F8DEDA", +"`. c #B76C57", +" + c #D76E4E", +".+ c #F89463", +"++ c #F9A36A", +"@+ c #FFB783", +"#+ c #F5A27A", +"$+ c #D0744E", +"%+ c #EB9060", +"&+ c #E68655", +"*+ c #EA8855", +"=+ c #F1935B", +"-+ c #F0975D", +";+ c #D27B43", +">+ c #E18450", +",+ c #E98B5A", +"'+ c #DD7C50", +")+ c #D07242", +"!+ c #F9A06A", +"~+ c #FFA771", +"{+ c #F6A26B", +"]+ c #EE9D67", +"^+ c #EEA26D", +"/+ c #F2AA77", +"(+ c #ECA776", +"_+ c #EDAC7B", +":+ c #EEB17D", +"<+ c #F1A55D", +"[+ c #FFA45C", +"}+ c #DC855E", +"|+ c #D9A3A2", +"1+ c #F5F0FC", +"2+ c #E9F7FA", +"3+ c #F6FDFE", +"4+ c #FDFBFE", +"5+ c #F8F9F9", +"6+ c #D1CFD0", +"7+ c #CCB9C0", +"8+ c #F9FAF9", +"9+ c #FBFAFC", +"0+ c #F7F0F5", +"a+ c #D7C6D1", +"b+ c #E7E0EB", +"c+ c #EAF4FB", +"d+ c #F1F9FD", +"e+ c #F9FEFF", +"f+ c #F2FCFB", +"g+ c #F6F5F5", +"h+ c #CA9E8E", +"i+ c #F4A27A", +"j+ c #FAA77A", +"k+ c #F6B280", +"l+ c #F5C896", +"m+ c #FED8AD", +"n+ c #FFCFAB", +"o+ c #FFCCA8", +"p+ c #F8C39B", +"q+ c #F5BC9C", +"r+ c #F2B48F", +"s+ c #ECA878", +"t+ c #F3A86C", +"u+ c #FCAA68", +"v+ c #FAA664", +"w+ c #F9A76A", +"x+ c #EC9B65", +"y+ c #D38048", +"z+ c #E69056", +"A+ c #E0874E", +"B+ c #FAA26B", +"C+ c #FAA470", +"D+ c #F5A06F", +"E+ c #F59E6A", +"F+ c #FA9C62", +"G+ c #F99A5D", +"H+ c #F49E6C", +"I+ c #F89E63", +"J+ c #FF9D5E", +"K+ c #ED8F64", +"L+ c #B67466", +"M+ c #F5EBF0", +"N+ c #E4F6F9", +"O+ c #EAFCFA", +"P+ c #FDFFFF", +"Q+ c #F5F8F8", +"R+ c #E6E6E7", +"S+ c #BEAAB2", +"T+ c #E9E2E6", +"U+ c #FCF9FB", +"V+ c #DFCFD2", +"W+ c #C4AEB7", +"X+ c #FAF0F9", +"Y+ c #EAF0F6", +"Z+ c #F3F8FC", +"`+ c #FBFEFF", +" @ c #F8F9F8", +".@ c #EADFDD", +"+@ c #B47A60", +"@@ c #E99560", +"#@ c #F3BB8E", +"$@ c #FDD8B6", +"%@ c #FFDDC1", +"&@ c #FDCFB2", +"*@ c #FECEAD", +"=@ c #FBD0A7", +"-@ c #F7D3A7", +";@ c #FAD1AA", +">@ c #F9CAA1", +",@ c #F8C392", +"'@ c #FAB179", +")@ c #F9A468", +"!@ c #F9A166", +"~@ c #F69F67", +"{@ c #F9A470", +"]@ c #FDA56E", +"^@ c #F69A5A", +"/@ c #D37536", +"(@ c #D1753D", +"_@ c #EF9868", +":@ c #F8A67A", +"<@ c #F39F71", +"[@ c #FB9E68", +"}@ c #FF9D60", +"|@ c #FA9C65", +"1@ c #FAA06B", +"2@ c #FA9C63", +"3@ c #FDA26C", +"4@ c #D5926E", +"5@ c #F2DFDA", +"6@ c #F0F3FD", +"7@ c #EDF3F8", +"8@ c #FEFCFC", +"9@ c #F9FAFA", +"0@ c #F3F4F6", +"a@ c #A2929B", +"b@ c #C0B1BA", +"c@ c #C4B0B0", +"d@ c #AC9398", +"e@ c #FEF1F8", +"f@ c #EEF2F7", +"g@ c #F2F3F8", +"h@ c #FEF9FB", +"i@ c #FBF2F0", +"j@ c #EFD9D8", +"k@ c #E09D81", +"l@ c #F0A268", +"m@ c #F9CCA1", +"n@ c #FDD3B7", +"o@ c #F2B094", +"p@ c #F3A377", +"q@ c #F5A66E", +"r@ c #F4A873", +"s@ c #F3A476", +"t@ c #F4A66D", +"u@ c #F6A367", +"v@ c #F9A269", +"w@ c #FBA169", +"x@ c #FD9F69", +"y@ c #FC9F69", +"z@ c #FC9F68", +"A@ c #F99F65", +"B@ c #F4A471", +"C@ c #F9B385", +"D@ c #F6A36E", +"E@ c #F19359", +"F@ c #D1743D", +"G@ c #E3905E", +"H@ c #F5A370", +"I@ c #F59F69", +"J@ c #FAA062", +"K@ c #FBA05E", +"L@ c #F8A26B", +"M@ c #F9A46F", +"N@ c #FAA160", +"O@ c #EA9C62", +"P@ c #C3998A", +"Q@ c #F7EBFA", +"R@ c #EEEAF8", +"S@ c #F6F4F6", +"T@ c #FCFEFF", +"U@ c #F4F4F7", +"V@ c #E4DCE3", +"W@ c #D4C1CD", +"X@ c #F2F5FA", +"Y@ c #AEA19F", +"Z@ c #C2B0B5", +"`@ c #F9F8FC", +" # c #E5F2F8", +".# c #EAF5FB", +"+# c #F0F5F5", +"@# c #F9F7F7", +"## c #D3B3A9", +"$# c #DF916B", +"%# c #FAA76E", +"&# c #F3B787", +"*# c #F0AE84", +"=# c #EE9D6B", +"-# c #F6A15D", +";# c #F7A559", +"># c #F9A160", +",# c #FE9B68", +"'# c #FD9D67", +")# c #FC9F67", +"!# c #FA9F69", +"~# c #F9A06C", +"{# c #F69F6A", +"]# c #F5A067", +"^# c #F9A464", +"/# c #F5A35C", +"(# c #E9A779", +"_# c #F8D5C1", +":# c #FFCEAA", +"<# c #FAB079", +"[# c #E1884B", +"}# c #CD713A", +"|# c #F39961", +"1# c #FAA56C", +"2# c #F8A668", +"3# c #FFA864", +"4# c #EF9965", +"5# c #E59462", +"6# c #FBA360", +"7# c #F49958", +"8# c #BE8469", +"9# c #E7DAE0", +"0# c #EFF2FB", +"a# c #EBF0F3", +"b# c #FBFEFE", +"c# c #F6F6FA", +"d# c #FAF3FA", +"e# c #B7A0AF", +"f# c #C4C0C8", +"g# c #D4CECD", +"h# c #DED5DD", +"i# c #EEF5FC", +"j# c #E4F0FD", +"k# c #E6F2FC", +"l# c #EBF5FB", +"m# c #EAE0E9", +"n# c #B67A69", +"o# c #ED8F5B", +"p# c #FCA368", +"q# c #F59E66", +"r# c #F9A067", +"s# c #F9A165", +"t# c #F99F66", +"u# c #FAA069", +"v# c #FAA169", +"w# c #FAA166", +"x# c #F8A264", +"y# c #F7A262", +"z# c #F9A162", +"A# c #F59E5E", +"B# c #FCA464", +"C# c #F0A172", +"D# c #F8C7AA", +"E# c #FFDFBE", +"F# c #F7D7AF", +"G# c #F7C497", +"H# c #F19C6B", +"I# c #DC7947", +"J# c #E48552", +"K# c #DD8553", +"L# c #BF6033", +"M# c #E28B60", +"N# c #E99B6D", +"O# c #F2A367", +"P# c #FA9F60", +"Q# c #E89874", +"R# c #E2CBBF", +"S# c #E9F6F7", +"T# c #EAF1FA", +"U# c #F6F6FB", +"V# c #FAF9FC", +"W# c #F9F1FA", +"X# c #BBABB5", +"Y# c #BDAEB7", +"Z# c #DDCBCC", +"`# c #FBF1F9", +" $ c #EFEAF7", +".$ c #E9EFFC", +"+$ c #EAF0FC", +"@$ c #F1F6FE", +"#$ c #E2CDCB", +"$$ c #D28869", +"%$ c #FFA26B", +"&$ c #F99F64", +"*$ c #FAA065", +"=$ c #FAA167", +"-$ c #FAA168", +";$ c #F9A066", +">$ c #F7A168", +",$ c #F7A167", +"'$ c #F7A165", +")$ c #F9A163", +"!$ c #FB9F63", +"~$ c #FA9E65", +"{$ c #F89D64", +"]$ c #FEA667", +"^$ c #F4B072", +"/$ c #FBD2AB", +"($ c #FBDFCB", +"_$ c #F9DECA", +":$ c #FBCBAA", +"<$ c #EFA579", +"[$ c #D3764B", +"}$ c #AE4621", +"|$ c #EA865A", +"1$ c #F8A674", +"2$ c #F8A16F", +"3$ c #FAA66A", +"4$ c #E38A65", +"5$ c #D5AFA0", +"6$ c #F1FDFF", +"7$ c #E9EFFF", +"8$ c #EEEDFC", +"9$ c #F5F4FD", +"0$ c #F0EDF6", +"a$ c #F5E9EF", +"b$ c #C6AFB4", +"c$ c #A28385", +"d$ c #FFF7FE", +"e$ c #F1E8F9", +"f$ c #EBEFF9", +"g$ c #EBEFFA", +"h$ c #F0EFF8", +"i$ c #D5B09E", +"j$ c #ED9B6E", +"k$ c #FDA168", +"l$ c #F89F66", +"m$ c #F89F65", +"n$ c #F6A066", +"o$ c #F5A166", +"p$ c #F6A065", +"q$ c #F8A065", +"r$ c #F9A167", +"s$ c #FCA06A", +"t$ c #F99B68", +"u$ c #DA7F51", +"v$ c #E88B52", +"w$ c #F9A15D", +"x$ c #F1AF7D", +"y$ c #F8D0B1", +"z$ c #FBDCC7", +"A$ c #FDDEC9", +"B$ c #FED4B9", +"C$ c #FBBC9A", +"D$ c #E58C65", +"E$ c #DB794C", +"F$ c #F69F61", +"G$ c #FF9F61", +"H$ c #FD9D60", +"I$ c #FAA163", +"J$ c #F79C6E", +"K$ c #DCA289", +"L$ c #EAE3E3", +"M$ c #ECF2FF", +"N$ c #E7F0FB", +"O$ c #E7F3FA", +"P$ c #E7EFF2", +"Q$ c #FEF7F9", +"R$ c #B49DA0", +"S$ c #C0A5A8", +"T$ c #F7F6FB", +"U$ c #E9EAFB", +"V$ c #E9F0F8", +"W$ c #E9F0FA", +"X$ c #F5F1FA", +"Y$ c #DBAD8E", +"Z$ c #EF975E", +"`$ c #FBA16A", +" % c #F7A065", +".% c #F6A165", +"+% c #F6A067", +"@% c #F6A570", +"#% c #F4A673", +"$% c #EC9A6C", +"%% c #D1794A", +"&% c #E68752", +"*% c #FDA26F", +"=% c #F2A374", +"-% c #F9C29B", +";% c #FFE0C1", +">% c #FDDDBC", +",% c #F4C29D", +"'% c #E09266", +")% c #D67F46", +"!% c #FB9E5C", +"~% c #FF9D63", +"{% c #FBA972", +"]% c #CE805C", +"^% c #C8A39D", +"/% c #F2F5FD", +"(% c #EAF1F4", +"_% c #E6F2F3", +":% c #E6F5F4", +"<% c #E7F1F1", +"[% c #EAEDED", +"}% c #E6E0E3", +"|% c #E7F3F7", +"1% c #DEF1FD", +"2% c #E7F2FB", +"3% c #EBF3FB", +"4% c #E7D7DC", +"5% c #D5916A", +"6% c #FCA265", +"7% c #F89E68", +"8% c #F8A066", +"9% c #F29F67", +"0% c #EFA56E", +"a% c #FBC490", +"b% c #F6BC8A", +"c% c #E9A26E", +"d% c #D8834F", +"e% c #E58456", +"f% c #FF9B6E", +"g% c #FAA16D", +"h% c #EDB075", +"i% c #F3C790", +"j% c #FCD7AD", +"k% c #FED4B6", +"l% c #F6BB94", +"m% c #CE8350", +"n% c #D6854A", +"o% c #FBA16F", +"p% c #F39F6D", +"q% c #F1A86D", +"r% c #E89568", +"s% c #D79F8D", +"t% c #F4EDEE", +"u% c #F0EEF8", +"v% c #ECEEF6", +"w% c #ECEFF9", +"x% c #ECEDF7", +"y% c #F1F0FC", +"z% c #F0F4FA", +"A% c #E6F2F5", +"B% c #DCF5FD", +"C% c #E3EBF7", +"D% c #F9FBFF", +"E% c #C19A96", +"F% c #D57E55", +"G% c #FDA366", +"H% c #F99F67", +"I% c #F99F63", +"J% c #FA9F63", +"K% c #F99E64", +"L% c #F8A86F", +"M% c #F1A66F", +"N% c #F8B985", +"O% c #FDD4A2", +"P% c #F2BD89", +"Q% c #F5A971", +"R% c #E28955", +"S% c #D97847", +"T% c #F69962", +"U% c #F4A66A", +"V% c #E9A46A", +"W% c #F2AA79", +"X% c #F9AE84", +"Y% c #F6AB7C", +"Z% c #EA9B63", +"`% c #E49159", +" & c #FFA572", +".& c #FBA36B", +"+& c #F8A363", +"@& c #FFA66F", +"#& c #CE7F5A", +"$& c #E9CAC3", +"%& c #F2F3FF", +"&& c #EBEDFD", +"*& c #F1EFFF", +"=& c #F8F1FF", +"-& c #FAEFFE", +";& c #FDF8FF", +">& c #FCF4F9", +",& c #F4F9FA", +"'& c #F9F7FF", +")& c #FDE9EB", +"!& c #D99781", +"~& c #F59668", +"{& c #F8A165", +"]& c #F8A164", +"^& c #F7A063", +"/& c #F9A164", +"(& c #FBA069", +"_& c #D98350", +":& c #DA8954", +"<& c #E79A68", +"[& c #FAB887", +"}& c #F6B181", +"|& c #F5A46D", +"1& c #F4A15F", +"2& c #E6914E", +"3& c #D37D41", +"4& c #EA9569", +"5& c #F8A078", +"6& c #FC9E6C", +"7& c #FE9D5C", +"8& c #FF9F5B", +"9& c #FFA46B", +"0& c #E58B5F", +"a& c #F09769", +"b& c #F39562", +"c& c #F09762", +"d& c #EF9A6A", +"e& c #D67F58", +"f& c #BB8678", +"g& c #F6F6FF", +"h& c #F7F4FF", +"i& c #EADFE9", +"j& c #D8C4CE", +"k& c #DABEC8", +"l& c #E3C8DB", +"m& c #E9CAD1", +"n& c #ECD7D4", +"o& c #EEDFE4", +"p& c #B98787", +"q& c #D9805B", +"r& c #F9A266", +"s& c #F6A360", +"t& c #F79E64", +"u& c #F6A466", +"v& c #F6A465", +"w& c #F9A065", +"x& c #FD9E67", +"y& c #DC7E4D", +"z& c #C7693C", +"A& c #ED9167", +"B& c #F4976B", +"C& c #FBA160", +"D& c #FFAC67", +"E& c #F49B60", +"F& c #D6784A", +"G& c #E5895F", +"H& c #F09662", +"I& c #FFA866", +"J& c #FFAD6E", +"K& c #E07F5D", +"L& c #7B2B1B", +"M& c #853D24", +"N& c #963E27", +"O& c #8D472B", +"P& c #824730", +"Q& c #843A2A", +"R& c #712A23", +"S& c #BA9092", +"T& c #DABABA", +"U& c #8B6E6B", +"V& c #4D3232", +"W& c #5D2D3D", +"X& c #68353A", +"Y& c #734744", +"Z& c #6A4A4C", +"`& c #663235", +" * c #934833", +".* c #DF8766", +"+* c #F99766", +"@* c #FB9E61", +"#* c #FFA66E", +"$* c #FCA16D", +"%* c #F99E69", +"&* c #F7A169", +"** c #F3A266", +"=* c #F4A365", +"-* c #FB9F68", +";* c #F6A16A", +">* c #F6A16B", +",* c #FCA06C", +"'* c #FC9D69", +")* c #FF9D6B", +"!* c #FF9E6C", +"~* c #F69563", +"{* c #D67949", +"]* c #D47348", +"^* c #F79567", +"/* c #FA9F68", +"(* c #F9A265", +"_* c #FFA166", +":* c #FC9B65", +"<* c #E98D5B", +"[* c #C4683A", +"}* c #BE6339", +"|* c #B06D4E", +"1* c #732F25", +"2* c #64201E", +"3* c #8B463B", +"4* c #B6573A", +"5* c #D06B39", +"6* c #D37A42", +"7* c #F4986B", +"8* c #FC9C73", +"9* c #F99F6C", +"0* c #F4A766", +"a* c #F1A561", +"b* c #F49E63", +"c* c #FB9E6B", +"d* c #F7A069", +"e* c #F9A16A", +"f* c #FCA16C", +"g* c #FE9F6C", +"h* c #FFA06C", +"i* c #FBA468", +"j* c #F49D5F", +"k* c #ED925B", +"l* c #C86A3A", +"m* c #DF8653", +"n* c #FBA26F", +"o* c #F9A369", +"p* c #FFA673", +"q* c #F6936D", +"r* c #7C1705", +"s* c #7C3625", +"t* c #C76E51", +"u* c #DE7B53", +"v* c #CA693D", +"w* c #BF633B", +"x* c #E88C57", +"y* c #E98E54", +"z* c #F9A267", +"A* c #FEA86F", +"B* c #F4A167", +"C* c #F6A362", +"D* c #F19C5B", +"E* c #DD8848", +"F* c #E89255", +"G* c #E68F53", +"H* c #F49D63", +"I* c #FEA76D", +"J* c #FCA36A", +"K* c #FAA466", +"L* c #F29B5B", +"M* c #EC8E5C", +"N* c #DB8154", +"O* c #D6874F", +"P* c #E79659", +"Q* c #FFA778", +"R* c #D07B64", +"S* c #6E1913", +"T* c #6C1F18", +"U* c #963729", +"V* c #EC9366", +"W* c #FFB374", +"X* c #E98F56", +"Y* c #B24C23", +"Z* c #ED8661", +"`* c #E78B58", +" = c #FAA561", +".= c #F8A262", +"+= c #F6A164", +"@= c #F7A466", +"#= c #E49459", +"$= c #C16E36", +"%= c #E08C58", +"&= c #E1895C", +"*= c #EF9265", +"== c #FFA372", +"-= c #FEA36A", +";= c #F5A268", +">= c #F6AA6A", +",= c #DC8545", +"'= c #D47440", +")= c #C87153", +"!= c #69241A", +"~= c #AB5E46", +"{= c #E88666", +"]= c #E37B53", +"^= c #D26E43", +"/= c #F4996C", +"(= c #CC6C39", +"_= c #E5834A", +":= c #F39462", +"<= c #FA9F6F", +"[= c #F6A16D", +"}= c #F49F6B", +"|= c #F69E6D", +"1= c #DD7F55", +"2= c #C7653C", +"3= c #E7825E", +"4= c #E4895D", +"5= c #F1A364", +"6= c #FFAC66", +"7= c #FEA067", +"8= c #CD7151", +"9= c #6E2215", +"0= c #7F2427", +"a= c #902F20", +"b= c #E5895A", +"c= c #FFB175", +"d= c #F2915D", +"e= c #B7522B", +"f= c #C05D34", +"g= c #D67649", +"h= c #F69E68", +"i= c #FDA46B", +"j= c #FCA069", +"k= c #FFA46E", +"l= c #F49460", +"m= c #EB8E5D", +"n= c #D06F41", +"o= c #C9683C", +"p= c #D67D55", +"q= c #A55135", +"r= c #682616", +"s= c #8F4C2E", +"t= c #DE8C68", +"u= c #CA6E51", +"v= c #C4654C", +"w= c #FFA579", +"x= c #F09360", +"y= c #CC7345", +"z= c #DA844C", +"A= c #EE9556", +"B= c #F59D5E", +"C= c #FFB174", +"D= c #FFB075", +"E= c #FFB073", +"F= c #FFA472", +"G= c #B85D49", +"H= c #6C1515", +"I= c #8B5446", +"J= c #73251B", +"K= c #95402C", +"L= c #E48F68", +"M= c #FFAA79", +"N= c #F59D70", +"O= c #EB9061", +"P= c #E48A59", +"Q= c #C57046", +"R= c #B26340", +"S= c #B16947", +"T= c #B36943", +"U= c #A65D40", +"V= c #7B3629", +"W= c #6A230D", +"X= c #BA6848", +"Y= c #D57C5E", +"Z= c #D1745E", +"`= c #CE7260", +" - c #923C2D", +".- c #84382F", +"+- c #813F39", +"@- c #7B423B", +" ", +" ", +" ", +" ", +" . + @ # $ % & * ", +" = - ; > , ' ) ! ~ { ] ^ / ( _ : < ", +"[ } | 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l ", +"m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W ", +"X Y Z ` ...+.@.#.$. %.&.*.=.-.;.>.,.'.).!.~.{.].^./.9 (._.:.<.[.}.|.1.2.3.4.5.6.7.8.9.0.", +"R a.b.c.d.e.f.R W g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.", +"R T.U.V.W.X.Y.V Z.`. +.+++@+#+$+%+&+*+=+-+;+>+,+'+)+!+~+{+]+^+/+(+_+:+<+[+}+|+1+2+3+4+5+6+7+8+9+", +"0+a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+u+v+w+x+y+z+A+B+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+", +"V+W+X+Y+Z+`+ @.@+@@@#@$@%@&@*@=@-@;@>@,@'@)@!@~@{@]@^@/@(@_@:@<@[@}@|@1@2@3@4@5@6@7@8@9@0@a@b@R ", +"c@d@e@f@g@h@i@j@k@l@m@n@o@p@q@r@s@t@u@v@w@x@y@z@A@B@C@D@E@F@G@H@I@J@K@L@M@N@O@P@Q@R@S@T@U@V@W@X@", +"Y@Z@`@ #.#+#@###$#%#&#*#=#-#;#>#,#'#)#!#~#{#]#^#/#(#_#:#<#[#}#|#1#2#3#4#5#6#7#8#9#0#a#b#c#d#e#f#", +"g#h#i#j#k#l#m#n#o#p#~@q#r#s#s#s#t#u#v#w#x#y#z#A#B#C#D#E#F#G#H#I#J#K#L#M#N#O#P#Q#R#S#T#U#V#W#X#Y#", +"Z#`# $.$+$@$#$$$%$&$&$*$=$-$r#r#;$>$,$'$)$)$!$~${$]$^$/$($_$:$<$[$}$|$1$2$~@3$4$5$6$7$8$9$0$a$b$", +"c$d$e$f$g$h$i$j$k$A@;$=$;$;$l$m$m$n$o$p$q$r$s$t$u$v$w$x$y$z$A$B$C$D$E$F$G$H$I$J$K$L$M$N$O$P$Q$R$", +"S$T$U$V$W$X$Y$Z$`$;$=$;$=$=$;$;$;$ % %.% %+%@%#%$%%%&%*%=%-%D ;%>%,%'%)%!%~%t#{%]%^%/%(%_%:%<%[%", +"}%|%1%2%3%4%5%6%7%r#=$m$;$;$=$;$8%&$&$q$+%9%0%a%b%c%d%e%f%g%h%i%j%k%l%m%n%o%p%q%r%s%t%u%v%w%x%y%", +"z%A%B%C%D%E%F%G%H%=$=$;$;$;$=$;$m$I%J%K%v@L%M%N%O%P%Q%R%S%T%U%V%W%X%Y%Z%`% &.&+&@&#&$&%&&&*&=&-&", +";&>&,&'&)&!&~&{&]&;$;$;$;$;$;$;$;$^&/&K%(&_&:&<&[&}&|&1&2&3&4&5&6&7&8&9&0&a&b&c&d&e&f&g&h&i&j&k&", +"l&m&n&o&p&q&=.r&s&t&t&r$;$;$m$;$r$u&v&w&x&t$y&z&A&B&x@C&D&E&F&G&H&I&J&K&L&M&N&O&P&Q&R&S&T&U&V& ", +"W&X&Y&Z&`& *.*+*@*#*$*%*&***=*A@-*;*>*,*'*)*!*~*{*]*^*/*(*_*:*<*[*}*|*1* 2* ", +" 3*4*5*6*7*8*9*0*a*b*c*d*e*f*g*h*z@i*j*k*l*m*n*8%o*p*q*r* ", +" s*t*u*v*w*x*y*z*A*B*C*D*E*F*G*H*I*J*K*L*M*N*O*P*Q*R*S* ", +" T*U*V*W*X*Y*Z*`* =.=+=@=#=$=%=&=*===-=;=>=,='=)=!= ", +" ~={=]=^=/=(=_=:=<=n*[=}=|=1=2=3=4=5=6=7=8=9= ", +" 0=a=b=c=d=e=f=g=o%h=i=j=k=l=m=n=o=p=q=r= ", +" s=t=u=v=w=x=y=z=A=B=C=D=E=F=G=H= ", +" I=J=K=L=M=N=O=P=Q=R=S=T=U=V= ", +" W=X=Y=Z=`= -.-+-@- ", +" ", +" ", +" "}; diff --git a/src/misc/stacktrace.cxx b/src/misc/stacktrace.cxx index 6660f6d3..401d260c 100644 --- a/src/misc/stacktrace.cxx +++ b/src/misc/stacktrace.cxx @@ -35,7 +35,11 @@ #include #include -#include "main.h" +#ifdef BUILD_FLDIGI +# include "main.h" +#else +# include "flarq.h" +#endif using namespace std; @@ -76,7 +80,11 @@ void diediedie(void) cerr << "\n****** Version information:\n" << version_text; string stfname; +#ifdef BUILD_FLDIGI stfname.assign(HomeDir).append("stacktrace.txt"); +#else + stfname = Logfile; +#endif #if !HAVE_DBG_STACK FILE* stfile = fopen(stfname.c_str(), "w");